2017-03-03 49 views
1

おはよう。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ですストリームをコピーするとき?私はどんな助けにも感謝します。

敬具

答えて

1

I dont calculate pts and dtsこれはあなたの問題です。フレームレートとビットレートは両方とも時間が分母である比率です。しかし、あなたはあなたが望むよりも短いビデオで終わるpts/dtsを書いていません。 h.264はすべてのフレームをタイムスタンプしません。コンテナジョブです。既知のフレームレートまたは別の値からタイムスタンプを作成する必要があります。

+0

回答ありがとうございます、szatmary。しかし、私はffmpegで初心者で、私は何をすべきかを完全に理解していません。私が持っている有用なフィールドは、入出力ストリームのAVStream構造体のtime_baseフィールドだけです。どのメソッドを使ってpts \ dtsを計算したか? – Bumblebee

+0

タイムベースは1/30という比率です。これは、タイムスタンプが1/30秒で前進することを意味します。したがって、1秒間に30フレームの場合、ptsはフレームごとに1ずつ増加します。タイムベースが1/3000の場合は、100だけインクリメントします。コーデックのコンテキストタイムベースを調べ、フレームタイムスタンプをそのベースに書き込みます。 – szatmary

+0

問題は、通常、私は入力ストリームのfpsを知らないということです。フィールドptsとdtsにはAV_NOPTS_VALUEが含まれているので、出力ストリームに対して正しいpts \ dtsを得るためにav_rescale_を呼び出すことはできません。 – Bumblebee

関連する問題