Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ FFMpeg:将h264流写入mp4容器而不进行更改_C++_Video_Ffmpeg_Stream - Fatal编程技术网

C++ FFMpeg:将h264流写入mp4容器而不进行更改

C++ FFMpeg:将h264流写入mp4容器而不进行更改,c++,video,ffmpeg,stream,C++,Video,Ffmpeg,Stream,你好 为简洁起见,该代码省略了错误处理和内存管理 我想捕获h264视频流,并将其打包到mp4容器中,不做任何更改。因为我不控制流的来源,所以我不能对流的结构进行假设。以这种方式,我必须探测输入流 AVProbeData probeData; probeData.buf_size = s->BodySize(); probeData.buf = s->GetBody(); probeData.filename = ""; AVInputForm

你好

为简洁起见,该代码省略了错误处理和内存管理

我想捕获h264视频流,并将其打包到mp4容器中,不做任何更改。因为我不控制流的来源,所以我不能对流的结构进行假设。以这种方式,我必须探测输入流

    AVProbeData probeData;
    probeData.buf_size = s->BodySize();
    probeData.buf = s->GetBody();
    probeData.filename = "";

    AVInputFormat* inFormat = av_probe_input_format(&probeData, 1);  
此代码正确定义了h264流

    AVProbeData probeData;
    probeData.buf_size = s->BodySize();
    probeData.buf = s->GetBody();
    probeData.filename = "";

    AVInputFormat* inFormat = av_probe_input_format(&probeData, 1);  
接下来,我创建输入格式上下文

    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);
    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);
    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);
此外,我写预告片并释放分配的内存。仅此而已。代码运行正常,我得到了可播放的mp4文件

现在的问题是:结果文件的流特征与源流的特征不完全一致。特别是,fps和比特率比它应该的要高

作为示例,下面是源流的输出ffplay.exe

 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  
对于结果流,包含部分源流

 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  
所以有一个问题,我在复制流时遗漏了什么?如果有任何帮助,我将不胜感激


致以最诚挚的问候

我不计算pts和dts这是你的问题。帧速率和比特率都是以时间为分母的比率。但如果不编写pts/dts,最终会得到比您想要的更短的视频。h、 264不会为每一帧添加时间戳。这就是容器的工作。您必须根据已知的帧速率或其他值制作时间戳。

谢谢您的回答,萨特玛丽。但我是ffmpeg的新手,我不完全明白我应该做什么。我仅有的有用字段是AVStream结构中用于输入和输出流的time_基字段。用于计算pts\dts的方法有哪些?时基是一个比率,比如说1/30,这意味着时间戳以1/30秒的速度向前移动。因此,如果每秒有30帧,pts将每帧增加一帧。如果时基为1/3000,它将增加100。查看编解码器上下文时基,并在该时基中写入帧时间戳。问题是,通常我不知道输入流的fps。字段pts和dts包含AV_NOPTS_值,因此我无法调用AV_rescale_u为输出流获取正确的pts\dts。ffmpeg也不知道。你一定是从什么地方弄来的。如果它是一个实时流,那么当你捕获每一帧时,你只需看看时钟就可以了。或者,您必须检查捕获设备的设置。