mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Live streaming v2
This commit is contained in:
parent
649b7e4ee6
commit
b97b8c369e
@ -76,13 +76,15 @@
|
|||||||
ret = AVERROR(ENOMEM);
|
ret = AVERROR(ENOMEM);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasAudio = false;
|
||||||
|
|
||||||
for (i = 0; i < input_format_context->nb_streams; i++) {
|
for (i = 0; i < input_format_context->nb_streams; i++) {
|
||||||
AVStream *out_stream;
|
AVStream *out_stream;
|
||||||
AVStream *in_stream = input_format_context->streams[i];
|
AVStream *in_stream = input_format_context->streams[i];
|
||||||
AVCodecParameters *in_codecpar = in_stream->codecpar;
|
AVCodecParameters *in_codecpar = in_stream->codecpar;
|
||||||
|
|
||||||
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO && in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
|
if (/*in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO && */in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
|
||||||
streams_list[i] = -1;
|
streams_list[i] = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -110,6 +112,8 @@
|
|||||||
ret = AVERROR_UNKNOWN;
|
ret = AVERROR_UNKNOWN;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasAudio = true;
|
||||||
|
|
||||||
// Set the codec parameters for the AAC encoder
|
// Set the codec parameters for the AAC encoder
|
||||||
aac_codec_context->sample_rate = in_codecpar->sample_rate;
|
aac_codec_context->sample_rate = in_codecpar->sample_rate;
|
||||||
@ -156,20 +160,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the resampling context
|
if (hasAudio) {
|
||||||
swr_ctx = swr_alloc_set_opts(NULL,
|
// Set up the resampling context
|
||||||
aac_codec_context->channel_layout, aac_codec_context->sample_fmt, aac_codec_context->sample_rate,
|
swr_ctx = swr_alloc_set_opts(NULL,
|
||||||
opus_decoder_context->channel_layout, opus_decoder_context->sample_fmt, opus_decoder_context->sample_rate,
|
aac_codec_context->channel_layout, aac_codec_context->sample_fmt, aac_codec_context->sample_rate,
|
||||||
0, NULL);
|
opus_decoder_context->channel_layout, opus_decoder_context->sample_fmt, opus_decoder_context->sample_rate,
|
||||||
if (!swr_ctx) {
|
0, NULL);
|
||||||
fprintf(stderr, "Could not allocate resampler context\n");
|
if (!swr_ctx) {
|
||||||
ret = AVERROR(ENOMEM);
|
fprintf(stderr, "Could not allocate resampler context\n");
|
||||||
goto end;
|
ret = AVERROR(ENOMEM);
|
||||||
}
|
goto end;
|
||||||
|
}
|
||||||
if ((ret = swr_init(swr_ctx)) < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize the resampling context\n");
|
if ((ret = swr_init(swr_ctx)) < 0) {
|
||||||
goto end;
|
fprintf(stderr, "Failed to initialize the resampling context\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
|
if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
|
||||||
|
@ -75,9 +75,9 @@ public final class MediaStreamComponent: CombinedComponent {
|
|||||||
var videoStalled: Bool = true
|
var videoStalled: Bool = true
|
||||||
|
|
||||||
var videoIsPlayable: Bool {
|
var videoIsPlayable: Bool {
|
||||||
!videoStalled && hasVideo
|
return true
|
||||||
|
//!videoStalled && hasVideo
|
||||||
}
|
}
|
||||||
// var wantsPiP: Bool = false
|
|
||||||
|
|
||||||
let deactivatePictureInPictureIfVisible = StoredActionSlot(Void.self)
|
let deactivatePictureInPictureIfVisible = StoredActionSlot(Void.self)
|
||||||
|
|
||||||
|
@ -806,116 +806,6 @@ private final class ProxyVideoView: UIView {
|
|||||||
|
|
||||||
self.id = Int64.random(in: Int64.min ... Int64.max)
|
self.id = Int64.random(in: Int64.min ... Int64.max)
|
||||||
|
|
||||||
/*if #available(iOS 13.0, *) {
|
|
||||||
do {
|
|
||||||
let server = try HTTPServer(port: NWEndpoint.Port(integerLiteral: 8012), tcpOptions: nil, queue: .main, handler: { request, response in
|
|
||||||
if request.url == "/master.m3u8" {
|
|
||||||
let _ = (call.externalMediaStream.get()
|
|
||||||
|> take(1)
|
|
||||||
|> mapToSignal { externalMediaStream in
|
|
||||||
return externalMediaStream.masterPlaylistData()
|
|
||||||
}
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { masterPlaylistData in
|
|
||||||
response.send(masterPlaylistData.data(using: .utf8)!)
|
|
||||||
})
|
|
||||||
} else if request.url == "/hls_level_0.m3u8" {
|
|
||||||
let _ = (call.externalMediaStream.get()
|
|
||||||
|> take(1)
|
|
||||||
|> mapToSignal { externalMediaStream in
|
|
||||||
return externalMediaStream.playlistData(quality: 0)
|
|
||||||
}
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { playlistData in
|
|
||||||
response.send(playlistData.data(using: .utf8)!)
|
|
||||||
})
|
|
||||||
} else if request.url == "/hls_level_1.m3u8" {
|
|
||||||
let _ = (call.externalMediaStream.get()
|
|
||||||
|> take(1)
|
|
||||||
|> mapToSignal { externalMediaStream in
|
|
||||||
return externalMediaStream.playlistData(quality: 1)
|
|
||||||
}
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { playlistData in
|
|
||||||
response.send(playlistData.data(using: .utf8)!)
|
|
||||||
})
|
|
||||||
} else if request.url.hasPrefix("/hls_stream0_") && request.url.hasSuffix(".ts") {
|
|
||||||
if let partIndex = Int(request.url[request.url.index(request.url.startIndex, offsetBy: "/hls_stream0_".count)..<request.url.index(request.url.endIndex, offsetBy: -".ts".count)]) {
|
|
||||||
let _ = (call.externalMediaStream.get()
|
|
||||||
|> take(1)
|
|
||||||
|> mapToSignal { externalMediaStream in
|
|
||||||
return externalMediaStream.partData(index: partIndex, quality: 0)
|
|
||||||
}
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { partData in
|
|
||||||
guard let partData else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let sourceTempFile = TempBox.shared.tempFile(fileName: "part.mp4")
|
|
||||||
let tempFile = TempBox.shared.tempFile(fileName: "part.ts")
|
|
||||||
defer {
|
|
||||||
TempBox.shared.dispose(sourceTempFile)
|
|
||||||
TempBox.shared.dispose(tempFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = try? partData.write(to: URL(fileURLWithPath: sourceTempFile.path))
|
|
||||||
|
|
||||||
let sourcePath = sourceTempFile.path
|
|
||||||
FFMpegLiveMuxer.remux(sourcePath, to: tempFile.path, offsetSeconds: Double(partIndex))
|
|
||||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: tempFile.path)) {
|
|
||||||
response.send(data)
|
|
||||||
} else {
|
|
||||||
let _ = try? response.send("Error")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
try response.send("Error")
|
|
||||||
}
|
|
||||||
} else if request.url.hasPrefix("/hls_stream1_") && request.url.hasSuffix(".ts") {
|
|
||||||
if let partIndex = Int(request.url[request.url.index(request.url.startIndex, offsetBy: "/hls_stream1_".count)..<request.url.index(request.url.endIndex, offsetBy: -".ts".count)]) {
|
|
||||||
let _ = (call.externalMediaStream.get()
|
|
||||||
|> take(1)
|
|
||||||
|> mapToSignal { externalMediaStream in
|
|
||||||
return externalMediaStream.partData(index: partIndex, quality: 1)
|
|
||||||
}
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { partData in
|
|
||||||
guard let partData else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let sourceTempFile = TempBox.shared.tempFile(fileName: "part.mp4")
|
|
||||||
let tempFile = TempBox.shared.tempFile(fileName: "part.ts")
|
|
||||||
defer {
|
|
||||||
TempBox.shared.dispose(sourceTempFile)
|
|
||||||
TempBox.shared.dispose(tempFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = try? partData.write(to: URL(fileURLWithPath: sourceTempFile.path))
|
|
||||||
|
|
||||||
let sourcePath = sourceTempFile.path
|
|
||||||
FFMpegLiveMuxer.remux(sourcePath, to: tempFile.path, offsetSeconds: Double(partIndex))
|
|
||||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: tempFile.path)) {
|
|
||||||
response.send(data)
|
|
||||||
} else {
|
|
||||||
let _ = try? response.send("Error")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
try response.send("Error")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try response.send("Error")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
self.server = server
|
|
||||||
server.resume()
|
|
||||||
} catch let e {
|
|
||||||
print("HTTPServer start error: \(e)")
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let assetUrl = "http://127.0.0.1:\(SharedHLSServer.shared.port)/\(call.internalId)/master.m3u8"
|
let assetUrl = "http://127.0.0.1:\(SharedHLSServer.shared.port)/\(call.internalId)/master.m3u8"
|
||||||
Logger.shared.log("MediaStreamVideoComponent", "Initializing HLS asset at \(assetUrl)")
|
Logger.shared.log("MediaStreamVideoComponent", "Initializing HLS asset at \(assetUrl)")
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@ -924,6 +814,7 @@ private final class ProxyVideoView: UIView {
|
|||||||
let asset = AVURLAsset(url: URL(string: assetUrl)!, options: [:])
|
let asset = AVURLAsset(url: URL(string: assetUrl)!, options: [:])
|
||||||
self.playerItem = AVPlayerItem(asset: asset)
|
self.playerItem = AVPlayerItem(asset: asset)
|
||||||
self.player = AVPlayer(playerItem: self.playerItem)
|
self.player = AVPlayer(playerItem: self.playerItem)
|
||||||
|
self.player.allowsExternalPlayback = true
|
||||||
self.playerLayer = AVPlayerLayer(player: self.player)
|
self.playerLayer = AVPlayerLayer(player: self.player)
|
||||||
|
|
||||||
super.init(frame: CGRect())
|
super.init(frame: CGRect())
|
||||||
|
@ -202,9 +202,9 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
var historyView: Signal<ChatHistoryViewUpdate, NoError>
|
var historyView: Signal<ChatHistoryViewUpdate, NoError>
|
||||||
|
|
||||||
let subject: ChatControllerSubject = .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: quote), timecode: nil)
|
let subject: ChatControllerSubject = .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: quote), timecode: nil, setupReply: false)
|
||||||
|
|
||||||
historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(subject: MessageHistoryInitialSearchSubject(location: searchLocation, quote: nil), count: 50, highlight: true), id: 0), context: self.context, chatLocation: preloadChatLocation, subject: subject, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), fixedCombinedReadStates: nil, tag: nil, additionalData: [])
|
historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(subject: MessageHistoryInitialSearchSubject(location: searchLocation, quote: nil), count: 50, highlight: true, setupReply: false), id: 0), context: self.context, chatLocation: preloadChatLocation, subject: subject, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), fixedCombinedReadStates: nil, tag: nil, additionalData: [])
|
||||||
|
|
||||||
var signal: Signal<(MessageIndex?, Bool), NoError>
|
var signal: Signal<(MessageIndex?, Bool), NoError>
|
||||||
signal = historyView
|
signal = historyView
|
||||||
|
@ -235,7 +235,7 @@ public final class ExternalMediaStreamingContext {
|
|||||||
playlistData.append("hls_stream\(quality)_\(index).ts\n")
|
playlistData.append("hls_stream\(quality)_\(index).ts\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Player: updating playlist \(quality) \(minIndex) ... \(headIndex)")
|
//print("Player: updating playlist \(quality) \(minIndex) ... \(headIndex)")
|
||||||
|
|
||||||
if quality == 0 {
|
if quality == 0 {
|
||||||
self.playlistData.set(.single(playlistData))
|
self.playlistData.set(.single(playlistData))
|
||||||
@ -393,6 +393,8 @@ public final class SharedHLSServer {
|
|||||||
case let .failed(error):
|
case let .failed(error):
|
||||||
Logger.shared.log("SharedHLSServer", "Server failed with error: \(error)")
|
Logger.shared.log("SharedHLSServer", "Server failed with error: \(error)")
|
||||||
self.listener?.cancel()
|
self.listener?.cancel()
|
||||||
|
|
||||||
|
self.listener?.start(queue: self.queue.queue)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user