mux raw h 264 to an mp4 file, some odd errors

删除回忆录丶 提交于 2019-12-23 02:01:33

问题


What I'm doing is on an IOS app with Xcode 7.3.

I got h264 data from an ip camera using UDP,the data can be decoded and displayed rightly (decoded by ffmpeg). Now I want to mux the raw H264 data to an mp4 file(some users may want to record what they are watching on his cell-phone), using ffmpeg. Nothing wrong happened when the code is running, and the result file can be played normally with QuickTime on my computer. But when played on iphone with iphone's default video player, it can't be played normally.Here is my code.

Wish someone could tell me what should I do, thanks!

init

AVFormatContext *formatContext;
AVOutputFormat *outputFormat;
AVStream *video_st;
int STREAM_FRAME_RATE = 15;
unsigned long video_PTS;
int initRecorder(char *fileName, int width, int height) {
    video_st = NULL;
    video_PTS = 0;

    av_register_all();

    outputFormat = av_guess_format(NULL, fileName, NULL);
    if (!outputFormat) {
        zj_printf("av_guess_format -> fail\n");
        return -1;
    }
    outputFormat->video_codec = AV_CODEC_ID_H264;

    avformat_alloc_output_context2(&formatContext, NULL, NULL, fileName);
    if (!formatContext) {
        zj_printf("avformat_alloc_context -> fail\n");
        return -2;
    }
    formatContext->oformat = outputFormat;
    strcpy(formatContext->filename, fileName);

    video_st = add_video_stream(formatContext, outputFormat, width, height);
    if (!video_st || open_video(formatContext, video_st)) {
        zj_printf("Could not open video codec\n");
        return -3;
    }

    av_dump_format(formatContext, 0, fileName, 1);
    if (!(outputFormat->flags & AVFMT_NOFILE)) {
        if (avio_open(&formatContext->pb, fileName, AVIO_FLAG_READ_WRITE) < 0) {
            zj_printf("could not open file: %s\n", fileName);
            return -7;
        }
    }

    /* write the stream header, if any */
    if (avformat_write_header(formatContext, NULL)) {
        zj_printf("avformat_write_header -> fail\n");
    }

    return 0;
}

add video stream and open

static AVStream * add_video_stream(AVFormatContext *pFormatContext, AVOutputFormat *pOutputFormat, int wight, int height) {

    AVStream *stream = avformat_new_stream(pFormatContext, NULL);
    if (!stream) {
        zj_fprintf(stderr, "Could not alloc stream\n");
        return NULL;
    }
    stream->id = 0;

    AVCodecContext *codecContext = stream->codec;
    codecContext->codec_id = pOutputFormat->video_codec;
    codecContext->codec_type = AVMEDIA_TYPE_VIDEO;

    /* resolution must be a multiple of two */
    codecContext->width = wight;
    codecContext->height = height;
    /* time base: this is the fundamental unit of time (in seconds) in terms
     of which frame timestamps are represented. for fixed-fps content,
     timebase should be 1/framerate and timestamp increments should be
     identically 1. */
    if (wight==1280 && height == 720) {
        codecContext->bit_rate = 512000;
        STREAM_FRAME_RATE = 15;
    } else {
        codecContext->bit_rate = 384000;
        STREAM_FRAME_RATE = 20;
    }
    codecContext->time_base = (AVRational){1,STREAM_FRAME_RATE};
    stream->time_base = (AVRational){1,STREAM_FRAME_RATE};
    codecContext->max_b_frames = 0;
    codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
    // these are the encoding params, here we do not need them
    // codecContext->gop_size = 12;   //10
    // codecContext->me_range = 16;
    // codecContext->max_qdiff = 4;
    // codecContext->qmin = 10;
    // codecContext->qmax = 31;

    if (pFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
        codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;

    return stream;
}

static int open_video(AVFormatContext *pFormatContext, AVStream *pStream) {
    /* find the video encoder */
    AVCodec *codec = avcodec_find_encoder(pStream->codec->codec_id);
    if (!codec) {
        return -1;
    }

    /* open the codec */
    if (avcodec_open2(pStream->codec, codec, NULL)) {
        return -2;
    }

    return 0;
}

write video frame

static int write_video_frame(char *buffer, int size) {
    int ret = 0;

    if (size > 0) {
        AVPacket mAVPacket;
        av_init_packet(&mAVPacket);
        mAVPacket.flags = isIFrame(buffer, size);
        mAVPacket.stream_index = video_st->index;

        mAVPacket.data = buffer;
        mAVPacket.size = size;
        mAVPacket.pts = video_PTS;
        mAVPacket.dts = video_PTS;
        video_PTS += 1;

        mAVPacket.pts = av_rescale_q_rnd(mAVPacket.pts, video_st->codec->time_base, video_st->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        mAVPacket.dts = av_rescale_q_rnd(mAVPacket.dts, video_st->codec->time_base, video_st->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        mAVPacket.duration = 0;
        mAVPacket.pos = -1;

        ret = av_interleaved_write_frame(formatContext, &mAVPacket);
        }

        av_packet_unref(&mAVPacket);


    } else {
        ret = -2;
    }

    if (ret != 0) {
        zj_printf("av_write_frame error:%d\n", ret);
    }

    return ret;
}

set the extradata in the codec context

unsigned char sps_pps[23] = {0x00, 0x00, 0x00, 0x01, 0x67, 0x64, 0x00, 0x29, 0xac, 0x1b, 0x1a, 0xc1, 0xe0, 0x51, 0x90, 0x00, 0x00, 0x00, 0x01, 0x68, 0xea, 0x43, 0xcb};
codecContext->extradata_size = 23;
codecContext->extradata = av_malloc(23 + AV_INPUT_BUFFER_PADDING_SIZE);
if (codecContext->extradata == NULL) {
    printf("could not av_malloc the video params extradata!\n");
    return -1;
}
memcpy(codecContext->extradata, sps_pps, 23);

回答1:


Your bitstream format is annex b. You must convert to the MP4 format by replacing start codes with nal length values. You must also populate the extradata in the codeccontext. Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream



来源:https://stackoverflow.com/questions/39012402/mux-raw-h-264-to-an-mp4-file-some-odd-errors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!