我想将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;
}