FFmpeg HLS select 流并且只检索它们的数据
FFmpeg HLS select streams and only retrieve their data
使用 avformat_open_input
打开 HLS 流会从所有流中检索数据,我只想从其中一些流中检索数据。这可能吗?
考虑以下 MWE:
#include <libavformat/avformat.h>
int main(int argc, char **argv)
{
AVFormatContext *inFmtCtx = NULL;
AVPacket packet;
const char *inUrl;
int ret;
if (argc < 2) { return -1; }
inUrl = argv[1];
if ((ret = avformat_open_input(&inFmtCtx, inUrl, NULL, NULL)) < 0)
goto end;
if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0)
goto end;
while (1) {
ret = av_read_frame(inFmtCtx, &packet);
if (ret < 0) break;
// # Placeholder: Do Something # //
printf("%i, ", packet.stream_index);
av_packet_unref(&packet);
}
end:
avformat_close_input(&inFmtCtx);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
使用示例 HLS url“http://mcdn.daserste.de/daserste/de/master.m3u8”(可能被地理锁定),printf
returns 0
和 9
之间的值,表示检索了所有 10 个流(5 个视频,5 个音频)。
当然,也可以在阅读后丢弃除所选内容之外的所有内容,例如使用
if(packet.stream_index != selectedVideoStreamId && packet.stream_index != selectedAudioStreamId) {
av_packet_unref(&packet);
continue;
}
但是可以将输入上下文/ffmpeg 配置为仅检索选定的流,即不下载所有不需要的数据(未选定的流)吗?
您可以通过丢弃属于它的所有流来禁用 HLS 变体:
if ((ret = avformat_open_input(&inFmtCtx, inUrl, NULL, NULL)) < 0)
goto end;
// disable all but the last stream
for (i = 0; i < inFmtCtx->nb_streams - 1; ++i) {
AVStream *st = inFmtCtx->streams[i];
st->discard = AVDISCARD_ALL;
}
if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0)
goto end;
阅读您的流几秒钟会产生:
stream=0 pkt_count=0
stream=1 pkt_count=0
stream=2 pkt_count=0
stream=3 pkt_count=0
stream=4 pkt_count=0
stream=5 pkt_count=0
stream=6 pkt_count=0
stream=7 pkt_count=0
stream=8 pkt_count=998
stream=9 pkt_count=937
如您所见,即使启用了单个流,它也会读取与上一个播放列表中的多路复用 audio/video 流相对应的两个流。如果您需要比这更好的粒度,则必须修改 HLS 分路器。
使用 avformat_open_input
打开 HLS 流会从所有流中检索数据,我只想从其中一些流中检索数据。这可能吗?
考虑以下 MWE:
#include <libavformat/avformat.h>
int main(int argc, char **argv)
{
AVFormatContext *inFmtCtx = NULL;
AVPacket packet;
const char *inUrl;
int ret;
if (argc < 2) { return -1; }
inUrl = argv[1];
if ((ret = avformat_open_input(&inFmtCtx, inUrl, NULL, NULL)) < 0)
goto end;
if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0)
goto end;
while (1) {
ret = av_read_frame(inFmtCtx, &packet);
if (ret < 0) break;
// # Placeholder: Do Something # //
printf("%i, ", packet.stream_index);
av_packet_unref(&packet);
}
end:
avformat_close_input(&inFmtCtx);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
使用示例 HLS url“http://mcdn.daserste.de/daserste/de/master.m3u8”(可能被地理锁定),printf
returns 0
和 9
之间的值,表示检索了所有 10 个流(5 个视频,5 个音频)。
当然,也可以在阅读后丢弃除所选内容之外的所有内容,例如使用
if(packet.stream_index != selectedVideoStreamId && packet.stream_index != selectedAudioStreamId) {
av_packet_unref(&packet);
continue;
}
但是可以将输入上下文/ffmpeg 配置为仅检索选定的流,即不下载所有不需要的数据(未选定的流)吗?
您可以通过丢弃属于它的所有流来禁用 HLS 变体:
if ((ret = avformat_open_input(&inFmtCtx, inUrl, NULL, NULL)) < 0)
goto end;
// disable all but the last stream
for (i = 0; i < inFmtCtx->nb_streams - 1; ++i) {
AVStream *st = inFmtCtx->streams[i];
st->discard = AVDISCARD_ALL;
}
if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0)
goto end;
阅读您的流几秒钟会产生:
stream=0 pkt_count=0
stream=1 pkt_count=0
stream=2 pkt_count=0
stream=3 pkt_count=0
stream=4 pkt_count=0
stream=5 pkt_count=0
stream=6 pkt_count=0
stream=7 pkt_count=0
stream=8 pkt_count=998
stream=9 pkt_count=937
如您所见,即使启用了单个流,它也会读取与上一个播放列表中的多路复用 audio/video 流相对应的两个流。如果您需要比这更好的粒度,则必须修改 HLS 分路器。