convert mp4-ts using libav

2019-05-29 02:15发布

问题:

I'm trying to convert an mp4 file to mpegts using libav. The code works, but outputs a file that can not be played by any player.

Here is the input file (it is video only, no audio)

here is the code I have so far:

int convert(const char *input, const char *output)
{
AVFormatContext *inputContext = NULL;
AVFormatContext *outputContext = NULL;
AVCodecContext *input_codec_context = NULL;
AVCodecContext *output_codec_context = NULL;
AVCodec *output_codec = NULL;
AVCodec *input_codec = NULL;
AVStream *stream = NULL;
AVIOContext *avioContext = NULL;

av_register_all();
avformat_network_init();
avformat_alloc_output_context2(&outputContext, NULL, "mpegts", output);
avio_open(&avioContext, output, AVIO_FLAG_WRITE);
outputContext->pb = avioContext;
stream = avformat_new_stream(outputContext, output_codec);

avformat_open_input(&inputContext, input, NULL, NULL);

input_codec_context = inputContext->streams[0]->codec;
input_codec = avcodec_find_decoder(inputContext->streams[0]->codec->codec_id);
avcodec_open2(inputContext->streams[0]->codec, input_codec, NULL);
avformat_find_stream_info(inputContext, NULL);
outputContext->oformat = av_guess_format(NULL, output, NULL);
output_codec = input_codec;

output_codec_context = avcodec_alloc_context3(NULL);
avcodec_copy_context(output_codec_context, input_codec_context);

avcodec_open2(output_codec_context, output_codec, NULL);

AVPacket packet;
av_init_packet(&packet);

avformat_write_header(outputContext, NULL);
while (!av_read_frame(inputContext, &packet)) {

    av_write_frame(outputContext, &packet);
}
av_free_packet(&packet);

av_write_trailer(outputContext);
avformat_close_input(&inputContext);
avformat_free_context(inputContext);
avformat_free_context(outputContext);

return 0;
}

any help appreciated.

回答1:

mp4 and mpegts assume a different bitstream format for h264.

You need to insert h264_mp4toannexb to reformat the AVPacket you are getting.

To allocate the context

    AVBitStreamFilterContext *bsf = av_bitstream_filter_init("h264_mp4toannexb");

in your demux loop

    AVPacket new_pkt = *pkt;
    int ret = av_bitstream_filter_filter(bsfc, avctx, NULL,
                                         &new_pkt.data, &new_pkt.size,
                                         pkt->data, pkt->size,
                                         pkt->flags & AV_PKT_FLAG_KEY);
    if (ret > 0) {
        // non-zero positive, you have new memory allocated, 
        // keep it referenced in the AVBuffer
        av_free_packet(pkt);
        new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
                                       av_buffer_default_free, NULL, 0);
        // handle memory error here

    } else if (ret < 0) {
        // handle failure here

    }
    // ret == 0, no problems, nothing else to do
    *pkt = new_pkt;