在LibAV中强制全局标头

时间:2015-07-07 15:25:47

标签: c video ffmpeg libav libavformat

我尝试使用LibAV编写C程序,从网络摄像头获取输入视频并将其保存为H264 MP4文件。我正在修改一个可以节省网络摄像头的.ppm帧的工作程序。我无法转换AVPackets以便可以编写它们 - 具体来说,avformat_write_header()失败,并带有消息

[mp4 @ 0050c000] Codec for stream 0 does not use global headers but container format requires global headers
[mp4 @ 0050c000] Could not find tag for codec none in stream #0, codec not currently supported in container

调用显然是返回错误-22,但我找不到实际解释错误代码的地方。当我试图编写MP4时,如何强制avformat_write_header()添加全局标头?代码如下;其中一部分改编自this question,但我尝试将其从输入视频文件调整为网络摄像头。

int _tmain(int argc, _TCHAR* argv[])
{
    AVInputFormat *inputFormat = NULL;
    AVDictionary *inputDictionary= NULL;
    AVFormatContext *inputFormatCtx = NULL;
    AVFormatContext *outputFormatCtx = NULL;
    AVCodecContext *inputCodecCtxOrig = NULL;
    AVCodecContext *inputCodecCtx = NULL;
    AVCodecContext *outputCodecCtx;
    AVCodec *inputCodec = NULL;
    AVCodec *outputCodec = NULL;
    AVStream *stream = NULL;
    AVIOContext *avioContext = NULL;
    avcodec_register_all();
    av_register_all();
    avdevice_register_all();
    av_dict_set(&inputDictionary, "Logitech HD Pro Webcam C920", "video", 0);
    avformat_alloc_output_context2(&outputFormatCtx, NULL, NULL, "output.mp4");
    avio_open(&avioContext, "output.mp4", AVIO_FLAG_WRITE);
    outputFormatCtx->pb = avioContext;
    stream = avformat_new_stream(outputFormatCtx, outputCodec);
    inputFormat = av_find_input_format("dshow");
    int r = avformat_open_input(&inputFormatCtx, "video=Logitech HD Pro Webcam C920", inputFormat, &inputDictionary);
    if (r != 0) {
        fprintf(stderr, "avformat_open_input() failed with error %d!\n", r);
        return -1; }
    r = avformat_find_stream_info(inputFormatCtx, NULL);
    if (r != 0) {
        fprintf(stderr, "avformat_find_stream_info() failed!\n");
        return -1; }
    av_dump_format(inputFormatCtx, 0, "video=Logitech HD Pro Webcam C920", 0);
    unsigned int i;
    int videoStream;
    videoStream = -1;
    for (i = 0; i < inputFormatCtx->nb_streams; i++) {
        if (inputFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO {
            videoStream = i;
            break; }
    }
    if (videoStream == -1)
        { return -1; }
    inputCodecCtxOrig = inputFormatCtx->streams[videoStream]->codec;
    inputCodec = avcodec_find_decoder(inputCodecCtxOrig->codec_id);
    if (inputCodec == NULL) {
        fprintf(stderr, "avcodec_find_decoder() failed!\n");
        return -1; }
    else { printf("Supported codec!\n"); }
    inputCodecCtx = avcodec_alloc_context3(inputCodec);
    if (inputCodecCtx == NULL) {
        fprintf(stderr, "avcodec_alloc_context3() failed!\n");
        return -1; }
    if (avcodec_copy_context(inputCodecCtx, inputCodecCtxOrig) != 0) {
        fprintf(stderr, "avcodec_copy_context() failed!\n");
        return -1; }
    if (avcodec_open2(inputCodecCtx,inputCodec,&inputDictionary) < 0) {
        fprintf(stderr, "avcodec_open2() failed!\n");
        return -1; }
    outputFormatCtx->oformat = av_guess_format(NULL, "output.mp4", NULL);
    outputFormatCtx->oformat->flags |= AVFMT_GLOBALHEADER;
    outputCodecCtx = avcodec_alloc_context3(outputCodec);
    avcodec_copy_context(outputCodecCtx, inputCodecCtx);
    outputCodec = inputCodec;
    avcodec_open2(outputCodecCtx, outputCodec, NULL);
    AVPacket packet;
    printf("foo\n");
    int errnum = avformat_write_header(outputFormatCtx, &inputDictionary);
    printf("bar %d\n", errnum);
    while(av_read_frame(inputFormatCtx, &packet)>=0) {
        av_interleaved_write_frame(outputFormatCtx, &packet);
        av_free_packet(&packet);
    }
    avcodec_close(inputCodecCtx);
    avcodec_close(inputCodecCtxOrig);
    avformat_close_input(&inputFormatCtx);
    return 0;
}

1 个答案:

答案 0 :(得分:0)

  

如何强制avformat_write_header()添加全局标题

全局标头由编码器写入,之后多路复用器从编解码器的extra_data字段读取它们。因此,在调用avcodec_open2()之前,应在编解码器的上下文中设置此标志。

outputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  

[mp4 @ 0050c000]无法在流#0,编解码器中找到codec none的标记   容器目前不支持

您可以尝试显式设置编码器(即手动设置),或从原始输入codeccontext复制codeccontext。

outputCodec = av_codec_find_encoder(AV_CODEC_ID_H264);
if(!outputCodec) return -1; //no encoder found

outputCodecCtx = avcodec_alloc_context3(outputCodec);
avcodec_copy_context(outputCodecCtx, inputCodecCtxOrig); //copy from orig

//You have to make sure each field is populated correctly
//with debugger or assertations
assert(outputCodecCtx->codec_id == AV_CODEC_ID_H264); //etc

outputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if(avcodec_open2(outputCodecCtx, outputCodec, NULL) <0) return -1;