如何通过libavcodec编程将MPEGTS文件转换为FLV文件

时间:2014-05-09 07:42:13

标签: ffmpeg transformation libavcodec

我想将MPEGTS文件转换为带有libavcodec API的FLV文件(只是转换格式,视频/音频编解码器不会更改)。以下是我在网上找到的代码。经过一番黑客攻击,它可以生成一个无法播放的FLV文件。有什么线索可以解决这个问题吗?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/rational.h>
#include <libavdevice/avdevice.h>
#include <libavutil/mathematics.h>
#include <libswscale/swscale.h>

static AVStream* add_output_stream(AVFormatContext* output_format_context, AVStream* input_stream) {
    AVCodecContext* input_codec_context = NULL;
    AVCodecContext* output_codec_context = NULL;

    AVStream* output_stream = NULL;
    output_stream = avformat_new_stream(output_format_context, 0);
    if (!output_stream) {
        printf("Call av_new_stream function failed\n");
        return NULL;
    }

    input_codec_context = input_stream->codec;
    output_codec_context = output_stream->codec;

    output_codec_context->codec_id = input_codec_context->codec_id;
    output_codec_context->codec_type = input_codec_context->codec_type;
    // output_codec_context->codec_tag = input_codec_context->codec_tag;
    output_codec_context->codec_tag = av_codec_get_tag(output_format_context->oformat->codec_tag, input_codec_context->codec_id);
    output_codec_context->bit_rate = input_codec_context->bit_rate;
    output_codec_context->extradata = input_codec_context->extradata;
    output_codec_context->extradata_size = input_codec_context->extradata_size;

    if (av_q2d(input_codec_context->time_base) * input_codec_context->ticks_per_frame > av_q2d(input_stream->time_base) && av_q2d(input_stream->time_base) < 1.0 / 1000) {
        output_codec_context->time_base = input_codec_context->time_base;
        output_codec_context->time_base.num *= input_codec_context->ticks_per_frame;
    } else {
        output_codec_context->time_base = input_stream->time_base;
    }
    switch (input_codec_context->codec_type) {
    case AVMEDIA_TYPE_AUDIO:
        output_codec_context->channel_layout = input_codec_context->channel_layout;
        output_codec_context->sample_rate = input_codec_context->sample_rate;
        output_codec_context->channels = input_codec_context->channels;
        output_codec_context->frame_size = input_codec_context->frame_size;
        if ((input_codec_context->block_align == 1 && input_codec_context->codec_id == CODEC_ID_MP3) || input_codec_context->codec_id == CODEC_ID_AC3) {
            output_codec_context->block_align = 0;
        } else {
            output_codec_context->block_align = input_codec_context->block_align;
        }
        break;
    case AVMEDIA_TYPE_VIDEO:
        output_codec_context->pix_fmt = input_codec_context->pix_fmt;
        output_codec_context->width = input_codec_context->width;
        output_codec_context->height = input_codec_context->height;
        output_codec_context->has_b_frames = input_codec_context->has_b_frames;
        if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
            output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
        }
        // output_codec_context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
        break;
    default:
        break;
    }

    return output_stream;
}

int main(int argc, char* argv[]) {
    const char* input = argv[1];
    const char* output_prefix = NULL;
    char* segment_duration_check = 0;
    const char* index = NULL;
    char* tmp_index = NULL;
    const char* http_prefix = NULL;
    long max_tsfiles = 0;
    double prev_segment_time = 0;
    double segment_duration = 0;

    AVInputFormat* ifmt = NULL;
    AVOutputFormat* ofmt = NULL;
    AVFormatContext* ic = NULL;
    AVFormatContext* oc = NULL;
    AVStream* video_st = NULL;
    AVStream* audio_st = NULL;
    AVCodec* codec = NULL;
    AVDictionary* pAVDictionary = NULL;

    av_register_all();
    av_log_set_level(AV_LOG_DEBUG);

    char szError[256] = {0};
    int nRet = avformat_open_input(&ic, input, ifmt, &pAVDictionary);
    if (nRet != 0) {
        av_strerror(nRet, szError, 256);
        printf(szError);
        printf("\n");
        printf("Call avformat_open_input function failed!\n");
        return 0;
    }

    if (avformat_find_stream_info(ic, NULL) < 0) {
        printf("Call av_find_stream_info function failed!\n");
        return 0;
    }

    ofmt = av_guess_format(NULL, argv[2], NULL);
    if (!ofmt) {
        printf("Call av_guess_format function failed!\n");
        return 0;
    }

    oc = avformat_alloc_context();
    if (!oc) {
        printf("Call av_guess_format function failed!\n");
        return 0;
    }
    oc->oformat = ofmt;

    int video_index = -1, audio_index = -1;
    unsigned int i;
    for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
        switch (ic->streams[i]->codec->codec_type) {
        case AVMEDIA_TYPE_VIDEO:
            video_index = i;
            ic->streams[i]->discard = AVDISCARD_NONE;
            video_st = add_output_stream(oc, ic->streams[i]);
            if (video_st->codec->codec_id == CODEC_ID_H264) {
                video_st->codec->opaque = av_bitstream_filter_init("h264_mp4toannexb");
            }
            break;
        case AVMEDIA_TYPE_AUDIO:
            audio_index = i;
            ic->streams[i]->discard = AVDISCARD_NONE;
            audio_st = add_output_stream(oc, ic->streams[i]);
            if (audio_st->codec->codec_id == CODEC_ID_AAC && !audio_st->codec->extradata_size) {
                audio_st->codec->opaque = av_bitstream_filter_init("aac_adtstoasc");
            }
            break;
        default:
            ic->streams[i]->discard = AVDISCARD_ALL;
            break;
        }
    }
    codec = avcodec_find_decoder(video_st->codec->codec_id);
    if (codec == NULL) {
        printf("Call avcodec_find_decoder function failed!\n");
        return 0;
    }

    if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
        printf("Call avcodec_open function failed !\n");
        return 0;
    }

    if (avio_open(&oc->pb, argv[2], AVIO_FLAG_WRITE) < 0) {
        return 0;
    }

    if (avformat_write_header(oc, &pAVDictionary)) {
        printf("Call avformat_write_header function failed.\n");
        return 0;
    }

    int decode_done = 0;
    do {
        AVPacket packet;
        decode_done = av_read_frame(ic, &packet);
        if (decode_done < 0) {
            break;
        }

        if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY) && video_st->codec->opaque != NULL) {
            AVPacket pkt = packet;
            int a = av_bitstream_filter_filter(video_st->codec->opaque, video_st->codec, NULL, &pkt.data, &pkt.size,
                    packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);
            if (a == 0) {
                memmove(packet.data, pkt.data, pkt.size);
                packet.size = pkt.size;
            } else if (a > 0) {
                packet = pkt;
            }
        }
        else if (packet.stream_index == audio_index && audio_st->codec->opaque != NULL) {
            AVPacket pkt = packet;
            int a = av_bitstream_filter_filter(audio_st->codec->opaque, audio_st->codec, NULL, &pkt.data, &pkt.size,
                    packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);
            if (a == 0) {
                memmove(packet.data, pkt.data, pkt.size);
                packet.size = pkt.size;
            } else if (a > 0) {
                packet = pkt;
            }
        }
        nRet = av_interleaved_write_frame(oc, &packet);
        if (nRet < 0) {
            printf("Call av_interleaved_write_frame function failed\n");
        } else if (nRet > 0) {
            printf("End of stream requested\n");
            av_free_packet(&packet);
                break;
        }
        av_free_packet(&packet);
    } while(!decode_done);

    av_write_trailer(oc);

    av_bitstream_filter_close(video_st->codec->opaque);  
    av_bitstream_filter_close(audio_st->codec->opaque);  
    avcodec_close(video_st->codec);
    unsigned int k;
    for(k = 0; k < oc->nb_streams; k++) {
        av_freep(&oc->streams[k]->codec);
        av_freep(&oc->streams[k]);
    }
    av_free(oc);
    getchar();
    return 0;
}

0 个答案:

没有答案