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);
|
||||
goto end;
|
||||
}
|
||||
|
||||
bool hasAudio = false;
|
||||
|
||||
for (i = 0; i < input_format_context->nb_streams; i++) {
|
||||
AVStream *out_stream;
|
||||
AVStream *in_stream = input_format_context->streams[i];
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
@ -110,6 +112,8 @@
|
||||
ret = AVERROR_UNKNOWN;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hasAudio = true;
|
||||
|
||||
// Set the codec parameters for the AAC encoder
|
||||
aac_codec_context->sample_rate = in_codecpar->sample_rate;
|
||||
@ -156,20 +160,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the resampling context
|
||||
swr_ctx = swr_alloc_set_opts(NULL,
|
||||
aac_codec_context->channel_layout, aac_codec_context->sample_fmt, aac_codec_context->sample_rate,
|
||||
opus_decoder_context->channel_layout, opus_decoder_context->sample_fmt, opus_decoder_context->sample_rate,
|
||||
0, NULL);
|
||||
if (!swr_ctx) {
|
||||
fprintf(stderr, "Could not allocate resampler context\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((ret = swr_init(swr_ctx)) < 0) {
|
||||
fprintf(stderr, "Failed to initialize the resampling context\n");
|
||||
goto end;
|
||||
if (hasAudio) {
|
||||
// Set up the resampling context
|
||||
swr_ctx = swr_alloc_set_opts(NULL,
|
||||
aac_codec_context->channel_layout, aac_codec_context->sample_fmt, aac_codec_context->sample_rate,
|
||||
opus_decoder_context->channel_layout, opus_decoder_context->sample_fmt, opus_decoder_context->sample_rate,
|
||||
0, NULL);
|
||||
if (!swr_ctx) {
|
||||
fprintf(stderr, "Could not allocate resampler context\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((ret = swr_init(swr_ctx)) < 0) {
|
||||
fprintf(stderr, "Failed to initialize the resampling context\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
|
||||
|
@ -75,9 +75,9 @@ public final class MediaStreamComponent: CombinedComponent {
|
||||
var videoStalled: Bool = true
|
||||
|
||||
var videoIsPlayable: Bool {
|
||||
!videoStalled && hasVideo
|
||||
return true
|
||||
//!videoStalled && hasVideo
|
||||
}
|
||||
// var wantsPiP: Bool = false
|
||||
|
||||
let deactivatePictureInPictureIfVisible = StoredActionSlot(Void.self)
|
||||
|
||||
|
@ -806,116 +806,6 @@ private final class ProxyVideoView: UIView {
|
||||
|
||||
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"
|
||||
Logger.shared.log("MediaStreamVideoComponent", "Initializing HLS asset at \(assetUrl)")
|
||||
#if DEBUG
|
||||
@ -924,6 +814,7 @@ private final class ProxyVideoView: UIView {
|
||||
let asset = AVURLAsset(url: URL(string: assetUrl)!, options: [:])
|
||||
self.playerItem = AVPlayerItem(asset: asset)
|
||||
self.player = AVPlayer(playerItem: self.playerItem)
|
||||
self.player.allowsExternalPlayback = true
|
||||
self.playerLayer = AVPlayerLayer(player: self.player)
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
@ -202,9 +202,9 @@ extension ChatControllerImpl {
|
||||
}
|
||||
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>
|
||||
signal = historyView
|
||||
|
@ -235,7 +235,7 @@ public final class ExternalMediaStreamingContext {
|
||||
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 {
|
||||
self.playlistData.set(.single(playlistData))
|
||||
@ -393,6 +393,8 @@ public final class SharedHLSServer {
|
||||
case let .failed(error):
|
||||
Logger.shared.log("SharedHLSServer", "Server failed with error: \(error)")
|
||||
self.listener?.cancel()
|
||||
|
||||
self.listener?.start(queue: self.queue.queue)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user