ffmpeg API h264编码视频不会在所有平台上播放 [英] ffmpeg API h264 encoded video does not play on all platforms
问题描述
编辑:在以前的版本中,我使用了一个非常老的ffmpeg API。我现在使用最新的库。这个问题只是从主到高稍有变化。
我正在使用ffmpeg C API在C ++中创建一个mp4视频。
我希望所得到的视频是配置文件受约束的基线,从而可以在尽可能多的平台上播放所产生的视频,特别是移动,但是我得到高配置文件,即使我将编解码器配置文件硬编码为 FF_PROFILE_H264_CONSTRAINED_BASELINE 。因此,视频不会在我们的所有测试平台上播放。
这是ffprobe video.mp4 -show_streams告诉我的视频流:
元数据:
/ pre>
major_brand:isom
minor_version:512
compatible_brands:isomiso2avc1mp41
creation_time: 1970-01-01 00:00:00
编码器:Lavf53.5.0
持续时间:00:00:13.20,开始:0.000000,比特率:553 kb / s
流#0:0 (和):视频:h264(主)(avc1 / 0x31637661),yuv420p,320x180,
424 kb / s,15 fps,15 tbr,15 tbn,30 tbc
元数据:
创建时间:1970-01-01 00:00:00
处理程序名称:VideoHandler
流#0:1(und):音频:aac(mp4a / 0x6134706D),44100 Hz,stereo,s16,12
kb / s
元数据:
creation_time:1970-01-01 00:00:00
handler_name:SoundHandler
------- VIDEO STREAM-- ------
[STREAM]
index = 0
codec_name = h264
codec_long_name = H.264 / AVC / MPEG-4 AVC / MPEG-4第10部分b
$ b profile = High< - 这应该是约束基线
codec_type = video
codec_time_base = 1/30
codec_tag_string = avc1
codec_tag = 0x31637661
width = 320
height = 180
has_b_frames = 0
sample_aspect_ratio = N / A
display_aspect_ratio = N / A
pix_fmt = yuv420p
level = 30
timecode = N / A
is_avc = 1
nal_length_size = 4
id = N / A
r_frame_rate = 15/1
avg_frame_rate = 15/1
time_base = 1/15
start_time = 0.000000
duration = 13.200000
bit_rate = 424252
nb_frames = 198
nb_read_frames = N / A
nb_read_packets = N / A
标签:creation_time = 1970-01-01 00:00:00
标签:language = und
标签:handler_name = VideoHandler
[/ STREAM]
------- AUDIO STREAM --------
[STREAM]
index = 1
codec_name = aac
codec_long_name =高级音频编码
profile = unknown
codec_type = audio
codec_time_base = 1/44100
codec_tag_string = mp4a
codec_tag = 0x6134706d
sample_fmt = s16
sample_rate = 44100
channels = 2
bits_per_sample = 0
id = N / A
r_frame_rate = 0/0
avg_frame_rate = 0/0
time_base = 1/44100
start_time = 0.000000
duration = 13.165714
bit_rate = 125301
nb_frames = 567
nb_read_frames = N / A
nb_read_packets = N / A
标签: creation_time = 1970-01-01 00:00:00
TAG:language = und
标签:handler_name = SoundHandler
[/ STREAM]
这是我用来添加视频流的功能。来自ptr->的所有值都是从外部定义的,那些值必须是具体的值才能得到正确的配置文件?:
static AVStream * add_video_stream(Cffmpeg_dll * ptr,AVFormatContext * oc,enum CodecID codec_id)
{
AVCodecContext * c;
AVStream * st;
AVCodec *编解码器
//获取正确的编解码器
codec = avcodec_find_encoder(codec_id);
if(!codec){
av_log(NULL,AV_LOG_ERROR,%s,Video codec not found\\\
);
exit(1);
}
//创建流
st = avformat_new_stream(oc,codec);
if(!st){
av_log(NULL,AV_LOG_ERROR,%s,Could not alloc stream\\\
);
exit(1);
}
c = st-> codec;
/ *获取默认值* /
codec = avcodec_find_encoder(codec_id);
if(!codec){
av_log(NULL,AV_LOG_ERROR,%s,未找到视频编解码器(默认值)\\\
);
exit(1);
}
avcodec_get_context_defaults3(c,codec);
c-> codec_id = codec_id;
c-> codec_type = AVMEDIA_TYPE_VIDEO;
c-> bit_rate = ptr-> video_bit_rate;
av_log(NULL,AV_LOG_ERROR,比特率:%i,c-> bit_rate);
c-> qmin = ptr-> qmin;
c-> qmax = ptr-> qmax;
c-> me_method = ptr-> me_method;
c-> me_subpel_quality = ptr-> me_subpel_quality;
c-> i_quant_factor = ptr-> i_quant_factor;
c-> qcompress = ptr-> qcompress;
c-> max_qdiff = ptr-> max_qdiff;
//我们需要设置级别和配置文件,以获得在所有平台上播放(希望)的视频
c-> level = 30;
c-> profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
c-> width = ptr-> dstWidth;
c-> height = ptr-> dstHeight;
c-> time_base.den = ptr-> fps;
c-> time_base.num = 1;
c-> gop_size = ptr-> fps;
c-> pix_fmt = STREAM_PIX_FMT;
c-> max_b_frames = 0;
//某些格式要流分头
if(oc-> oformat-> flags& AVFMT_GLOBALHEADER)
c-> flags | = CODEC_FLAG_GLOBAL_HEADER;
return st;
}
附加信息:
作为参考视频,我使用Mozilla作为一个在每个平台/浏览器上播放的示例的gizmo.mp4。它绝对有约束基线的概况,绝对适用于我们所有的测试智能手机。 您可以在这里下载。我们的自创视频无效平台,我相信这是因为个人资料。
我也使用 qt-faststart.exe 将标题移动到在创建mp4之后启动文件,因为这不能直接在C ++中以良好的方式完成。这可能是问题吗?
显然,我正在做一些错误,但我不知道它可能是什么。我会感谢每一个提示;)
解决方案我有解决方案。在ffmpeg错误跟踪器和浏览配置文件设置示例中花了一些时间和讨论后,我终于找出了解决方案。
需要使用av_opt_set(codecContext-> priv_data ,配置文件,基准(或任何其他所需的配置文件),AV_OPT_SEARCH_CHILDREN)
所以在我的情况下,将是:
错误:
//我们需要将级别和配置文件设置为获取所有平台上播放(希望)的视频
c-> level = 30;
c-> profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
正确:
//将配置文件设置为基线
av_opt_set(c-> priv_data,profile,baseline,AV_OPT_SEARCH_CHILDREN);
完全不直观,与其他API使用相反,但这是ffmpeg的理念。你不需要理解它,只需要了解如何使用它;)
Edit: In the previous version I used a very old ffmpeg API. I now use the newest libraries. The problem has only changed slightly, from "Main" to "High".
I am using the ffmpeg C API to create a mp4 video in C++.
I want the resulting video to be of the profile "Constrained Baseline", so that the resulting video can be played on as much platforms as possible, especially mobile, but I get "High" profile every time, even though I hard coded the codec profile to be FF_PROFILE_H264_CONSTRAINED_BASELINE. As a result, the video does not play on all our testing platforms.
This is what "ffprobe video.mp4 -show_streams" tells about my video streams:
Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 creation_time : 1970-01-01 00:00:00 encoder : Lavf53.5.0 Duration: 00:00:13.20, start: 0.000000, bitrate: 553 kb/s Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 320x180, 424 kb/s, 15 fps, 15 tbr, 15 tbn, 30 tbc Metadata: creation_time : 1970-01-01 00:00:00 handler_name : VideoHandler Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, s16, 12 kb/s Metadata: creation_time : 1970-01-01 00:00:00 handler_name : SoundHandler -------VIDEO STREAM-------- [STREAM] index=0 codec_name=h264 codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 profile=High <-- This should be "Constrained Baseline" codec_type=video codec_time_base=1/30 codec_tag_string=avc1 codec_tag=0x31637661 width=320 height=180 has_b_frames=0 sample_aspect_ratio=N/A display_aspect_ratio=N/A pix_fmt=yuv420p level=30 timecode=N/A is_avc=1 nal_length_size=4 id=N/A r_frame_rate=15/1 avg_frame_rate=15/1 time_base=1/15 start_time=0.000000 duration=13.200000 bit_rate=424252 nb_frames=198 nb_read_frames=N/A nb_read_packets=N/A TAG:creation_time=1970-01-01 00:00:00 TAG:language=und TAG:handler_name=VideoHandler [/STREAM] -------AUDIO STREAM-------- [STREAM] index=1 codec_name=aac codec_long_name=Advanced Audio Coding profile=unknown codec_type=audio codec_time_base=1/44100 codec_tag_string=mp4a codec_tag=0x6134706d sample_fmt=s16 sample_rate=44100 channels=2 bits_per_sample=0 id=N/A r_frame_rate=0/0 avg_frame_rate=0/0 time_base=1/44100 start_time=0.000000 duration=13.165714 bit_rate=125301 nb_frames=567 nb_read_frames=N/A nb_read_packets=N/A TAG:creation_time=1970-01-01 00:00:00 TAG:language=und TAG:handler_name=SoundHandler [/STREAM]
This is the function I use to add a video stream. All the values that come from ptr-> are defined from outside, do those values have to be specific values to get the correct profile?:
static AVStream *add_video_stream( Cffmpeg_dll * ptr, AVFormatContext *oc, enum CodecID codec_id ) { AVCodecContext *c; AVStream *st; AVCodec* codec; // Get correct codec codec = avcodec_find_encoder(codec_id); if (!codec) { av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found\n"); exit(1); } // Create stream st = avformat_new_stream(oc, codec); if (!st) { av_log(NULL, AV_LOG_ERROR, "%s","Could not alloc stream\n"); exit(1); } c = st->codec; /* Get default values */ codec = avcodec_find_encoder(codec_id); if (!codec) { av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found (default values)\n"); exit(1); } avcodec_get_context_defaults3(c, codec); c->codec_id = codec_id; c->codec_type = AVMEDIA_TYPE_VIDEO; c->bit_rate = ptr->video_bit_rate; av_log(NULL, AV_LOG_ERROR, " Bit rate: %i", c->bit_rate); c->qmin = ptr->qmin; c->qmax = ptr->qmax; c->me_method = ptr->me_method; c->me_subpel_quality = ptr->me_subpel_quality; c->i_quant_factor = ptr->i_quant_factor; c->qcompress = ptr->qcompress; c->max_qdiff = ptr->max_qdiff; // We need to set the level and profile to get videos that play (hopefully) on all platforms c->level = 30; c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE; c->width = ptr->dstWidth; c->height = ptr->dstHeight; c->time_base.den = ptr->fps; c->time_base.num = 1; c->gop_size = ptr->fps; c->pix_fmt = STREAM_PIX_FMT; c->max_b_frames = 0; // some formats want stream headers to be separate if(oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return st; }
Additional info:
As a reference video, I use the gizmo.mp4 that Mozilla serves as an example that plays on every platform/browser. It definitely has the "Constrained Baseline" profile, and definitely works on all our testing smartphones. You can download it here. Our self-created video doesn't work on all platforms and I'm convinced this is because of the profile.
I am also using qt-faststart.exe to move the headers to the start of the file after creating the mp4, as this cannot be done in a good way in C++ directly. Could that be the problem?
Obviously, I am doing something wrong, but I don't know what it could be. I'd be thankful for every hint ;)
解决方案I have the solution. After spending some time and discussions in the ffmpeg bug tracker and browsing for profile setting examples, I finally figured out the solution.
One needs to use av_opt_set(codecContext->priv_data, "profile", "baseline" (or any other desired profile), AV_OPT_SEARCH_CHILDREN)
So in my case that would be:
Wrong:
// We need to set the level and profile to get videos that play (hopefully) on all platforms c->level = 30; c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
Correct:
// Set profile to baseline av_opt_set(c->priv_data, "profile", "baseline", AV_OPT_SEARCH_CHILDREN);
Completely unintuitive and contrary to the rest of the API usage, but that's ffmpeg philosophy. You don't need to understand it, you just need to understand how to use it ;)
这篇关于ffmpeg API h264编码视频不会在所有平台上播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!