おはよう。FFMpeg:変更なしでMP4コンテナにh264ストリームを書き込む
簡潔にするため、コードではエラー処理とメモリ管理は省略されています。
私はh264ビデオストリームをキャプチャし、変更せずにmp4コンテナにパックしたいと考えています。私はストリームのソースを制御しないので、私はストリームの構造について仮定することはできません。このように私は入力ストリームを調べなければなりません。
AVProbeData probeData;
probeData.buf_size = s->BodySize();
probeData.buf = s->GetBody();
probeData.filename = "";
AVInputFormat* inFormat = av_probe_input_format(&probeData, 1);
このコードは、h264ストリームを正しく定義しています。
次に、私は、初期化が行われ
unsigned char* avio_output_buffer = reinterpret_cast<unsigned char*>(av_malloc(AVIO_BUFFER_SIZE));
AVIOContext* avio_output_ctx = avio_alloc_context(avio_output_buffer, AVIO_BUFFER_SIZE,
1, this, NULL, &write_packet, NULL);
AVFormatContext* ofmt_ctx = nullptr;
avformat_alloc_output_context2(&ofmt_ctx, NULL, "mp4", NULL);
ofmt_ctx->pb = avio_output_ctx;
AVDictionary* dict = nullptr;
av_dict_set(&dict, "movflags", "faststart", 0);
av_dict_set(&dict, "movflags", "frag_keyframe+empty_moov", 0);
AVStream* outVideoStream = avformat_new_stream(ofmt_ctx, nullptr);
avcodec_copy_context(outVideoStream->codec, ifmt_ctx->streams[0]->codec);
ret = avformat_write_header(ofmt_ctx, &dict);
、入力フォーマットのコンテキストを作成し、
unsigned char* avio_input_buffer = reinterpret_cast<unsigned char*> (av_malloc(AVIO_BUFFER_SIZE));
AVIOContext* avio_input_ctx = avio_alloc_context(avio_input_buffer, AVIO_BUFFER_SIZE,
0, this, &read_packet, NULL, NULL);
AVFormatContext* ifmt_ctx = avformat_alloc_context();
ifmt_ctx->pb = avio_input_ctx;
int ret = avformat_open_input(&ifmt_ctx, NULL, inFormat, NULL);
設定された画像サイズ、
ifmt_ctx->streams[0]->codec->width = ifmt_ctx->streams[0]->codec->coded_width = width;
ifmt_ctx->streams[0]->codec->height = ifmt_ctx->streams[0]->codec->coded_height = height;
出力形式コンテキストを作成します。さらに、h264ストリームからmp4コンテナへのパケットのシフトがあります。ソースパケットにはAV_NOPTS_VALUEが含まれているので、ptsとdtsは計算しません。
AVPacket pkt;
while (...)
{
ret = av_read_frame(ifmt_ctx, &pkt);
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
av_free_packet(&pkt);
}
さらに、私は予告編と空きメモリを書き込みます。それだけです。コードが動作し、私は再生可能なmp4ファイルを得た。
問題:結果のファイルのストリーム特性は、ソースストリームの特性に完全に一致しません。特に、fpsとビットレートは、それより高くなります。以下のサンプルとして
は、だから私は逃した何を疑問がある
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'd:/movies/target.mp4':f=0/0
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1iso6mp41
encoder : Lavf57.56.101
Duration: 00:00:11.64, start: 0.000000, bitrate: 18686 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1/0x31637661), yuv420p, 1920x1080, 18683 kb/s, 38.57 fps, 40 tbr, 90k tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
Switch subtitle stream from #-1 to #-1 vq= 2309KB sq= 0B f=0/0
5.70 M-V: 0.040 fd= 127 aq= 0KB vq= 2562KB sq= 0B f=0/0
(ソースストリームの一部を含む)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'd:/movies/source.mp4':0/0
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isom
creation_time : 2014-04-14T13:03:54.000000Z
Duration: 00:00:58.08, start: 0.000000, bitrate: 12130 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1/0x31637661),yuv420p, 1920x1080, 12129 kb/s, 25 fps, 25 tbr, 25 tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
Switch subtitle stream from #-1 to #-1 vq= 1428KB sq= 0B f=0/0
Seek to 49% (0:00:28) of total duration (0:00:58) B f=0/0
30.32 M-V: -0.030 fd= 87 aq= 0KB vq= 1360KB sq= 0B f=0/0
とストリームを結果のためのソースストリームのための出力ffplay.exeですストリームをコピーするとき?私はどんな助けにも感謝します。
敬具
回答ありがとうございます、szatmary。しかし、私はffmpegで初心者で、私は何をすべきかを完全に理解していません。私が持っている有用なフィールドは、入出力ストリームのAVStream構造体のtime_baseフィールドだけです。どのメソッドを使ってpts \ dtsを計算したか? – Bumblebee
タイムベースは1/30という比率です。これは、タイムスタンプが1/30秒で前進することを意味します。したがって、1秒間に30フレームの場合、ptsはフレームごとに1ずつ増加します。タイムベースが1/3000の場合は、100だけインクリメントします。コーデックのコンテキストタイムベースを調べ、フレームタイムスタンプをそのベースに書き込みます。 – szatmary
問題は、通常、私は入力ストリームのfpsを知らないということです。フィールドptsとdtsにはAV_NOPTS_VALUEが含まれているので、出力ストリームに対して正しいpts \ dtsを得るためにav_rescale_を呼び出すことはできません。 – Bumblebee