在用最新版 ffmpeg 2.0 转换视频的时候 首先遇到的一个问题是 在 avformat_write_header(pFormatCtxOut, NULL);
处报错:[mp4 @ 0x8183600] track 1: codec frame size is not set 虽然报了这个错误 但是还是能够转码,只是转出来的视频本来30秒 但是15秒左右就没有了,应该没有丢帧,只不过画面播放得特别快,就像快进一样。下面是源码,求大神 出场---
// Created by showself on 13-8-19.
// Copyright (c) 2013年 showself. All rights reserved.
//
#include
#include "test2.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
enum AVCodecID codec_id);
void transTest2(const char *src, const char *dst)
{
const char *filename;
const char *outfilename;
AVFormatContext *pFormatCtxIn,*pFormatCtxOut;
AVInputFormat *inFmt;
AVOutputFormat *outFmt;
AVStream *audio_st,*video_st;
AVFrame *pFrameIn;
AVCodecContext *pVideoCodecCtxIn,*pAudioCodecCtxIn,*pVideoCodecCtxOut,*pAudioCodecCtxOut;
AVCodec *pVideoCodecIn,*pAudioCodecIn,*pVideoCodecOut,*pAudioCodecOut;
int i ,videoStream,audioStream;;
int ret = 0;
AVPacket packet;
// int frame_count;
/* Initialize libavcodec, and register all codecs and formats. */
av_register_all();
if (src == NULL) {
printf("no input file");
return;
}
filename = src;
outfilename = dst;
/*get inout format*/
inFmt = av_find_input_format("MOV");
/*allocate the input media context*/
pFormatCtxIn = avformat_alloc_context();
if (pFormatCtxIn == NULL) {
printf("allocate the input media context error");
return;
}
// open a video
if (avformat_open_input(&pFormatCtxIn, filename, inFmt, NULL)) {
return;
}
// get stream info
if (avformat_find_stream_info(pFormatCtxIn, NULL)<0) {
return;
}
// get streams index from a video
videoStream = -1;
audioStream = -1;
for (i=0; i<pFormatCtxIn->nb_streams; i++) {
if(pFormatCtxIn->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
printf("%d stream 为视频\n",i);
videoStream=i;
}
if (pFormatCtxIn->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audioStream = i;// 音轨位置
printf("%d stream 为音轨\n",i);
}
}
if(videoStream==-1)
return ; // Didn't find a video stream or Did not find a audio stream
if (audioStream == -1) {
return;
}
// get decode codec contex pointer
pVideoCodecCtxIn = pFormatCtxIn->streams[videoStream]->codec;
pAudioCodecCtxIn = pFormatCtxIn->streams[audioStream]->codec;
// get decode codec pointer
pVideoCodecIn = avcodec_find_decoder(pVideoCodecCtxIn->codec_id);
if (pVideoCodecIn == NULL) {
return;
}
pAudioCodecIn = avcodec_find_decoder(pAudioCodecCtxIn->codec_id);
if (pAudioCodecIn == NULL) {
return;
}
// open codec
if (avcodec_open2(pVideoCodecCtxIn, pVideoCodecIn, NULL)<0) {
return;
}
if (avcodec_open2(pAudioCodecCtxIn, pAudioCodecIn, NULL)<0) {
return;
}
// allocate input frame
pFrameIn = av_frame_alloc();
if (pFrameIn == NULL) {
return;
}
/* allocate the output media context */
// // method 1
// avformat_alloc_output_context2(&pFormatCtxOut, NULL, NULL, outfilename);
// if (!pFormatCtxOut) {
// printf("Could not deduce output format from file extension: using MPEG.\n");
// avformat_alloc_output_context2(&pFormatCtxOut, NULL, "mpeg", outfilename);
// }
// if (!pFormatCtxOut) {
// return ;
// }
// method 2
outFmt = av_guess_format(NULL, outfilename, NULL);
if (outFmt == NULL) {
return;
}
pFormatCtxOut = avformat_alloc_context();
if (pFormatCtxOut == NULL) {
return;
}
pFormatCtxOut->oformat = outFmt;
sprintf(pFormatCtxOut->filename, "%s",outfilename);
// get output codec from AVOutputContext
pVideoCodecOut = avcodec_find_encoder(outFmt->video_codec);
if (pVideoCodecOut == NULL) {
return;
}
pAudioCodecOut = avcodec_find_encoder(outFmt->audio_codec);
if (pAudioCodecOut == NULL) {
return;
}
/* Add the audio and video streams using the default format codecs
* and initialize the codecs. */
video_st = NULL;
audio_st = NULL;
// 添加一条视频流
if (outFmt->video_codec != AV_CODEC_ID_NONE) {
// 解码 源视频流
video_st = avformat_new_stream(pFormatCtxOut, pVideoCodecOut);
if (video_st == NULL) {
return;
}
pVideoCodecCtxOut = video_st->codec;
pVideoCodecCtxOut->codec_type = AVMEDIA_TYPE_VIDEO;
pVideoCodecCtxOut->codec_id = outFmt->video_codec;
pVideoCodecCtxOut->bit_rate = pVideoCodecCtxIn->bit_rate/2;
pVideoCodecCtxOut->width = pVideoCodecCtxIn->width;
pVideoCodecCtxOut->height = pVideoCodecCtxIn->height;
pVideoCodecCtxOut->time_base.den = 25;
pVideoCodecCtxOut->time_base.num = 1;
pVideoCodecCtxOut->gop_size = 12;
pVideoCodecCtxOut->pix_fmt = PIX_FMT_YUV420P;
if (pVideoCodecCtxOut->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B frames */
pVideoCodecCtxOut->max_b_frames =2;
}
if (pVideoCodecCtxOut->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
/* Needed to avoid using macroblocks in which some coeffs overflow.
* This does not happen with normal video, it just happens here as
* the motion of the chroma plane does not match the luma plane. */
pVideoCodecCtxOut->mb_decision = 2;
}
}
if (pFormatCtxOut->oformat->flags & AVFMT_GLOBALHEADER)
{
pVideoCodecCtxOut->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
// 添加一条音频流
if (outFmt->audio_codec != AV_CODEC_ID_NONE) {
audio_st = avformat_new_stream(pFormatCtxOut, pAudioCodecOut);
if (audio_st == NULL) {
return;
}
pAudioCodecCtxOut = audio_st->codec;
pAudioCodecCtxOut->codec_id = outFmt->audio_codec;
pAudioCodecCtxOut->coder_type = AVMEDIA_TYPE_AUDIO;
pAudioCodecCtxOut->sample_fmt = pAudioCodecCtxIn->sample_fmt;
pAudioCodecCtxOut->bit_rate = pAudioCodecCtxIn->bit_rate;
pAudioCodecCtxOut->sample_rate = pAudioCodecCtxIn->sample_rate;
pAudioCodecCtxOut->channels = pAudioCodecCtxIn->channels;
pAudioCodecCtxOut->channel_layout = pAudioCodecCtxIn->channel_layout;
}
if (pFormatCtxOut->oformat->flags & AVFMT_GLOBALHEADER)
{
pAudioCodecCtxOut->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
// open encode codec
if (avcodec_open2(pVideoCodecCtxOut, pVideoCodecOut, NULL)<0) {
return;
}
// if(avcodec_open2(pAudioCodecCtxOut, pAudioCodecOut, NULL)<0)
// {
// printf("audio encode codec not found\n");
// return;
// }
av_dump_format(pFormatCtxOut, 0, outfilename, 1);
// open the output file, if needed
if (!(pFormatCtxOut->flags & AVFMT_NOFILE)) { //
if (avio_open(&pFormatCtxOut->pb, outfilename, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Could not open '%s'\n", outfilename);
return;
}
}
printf("1\n");
// write the stream header, if any
// [mp4 @ 0x99a8a00] track 1: codec frame size is not set?
avformat_write_header(pFormatCtxOut, NULL);
printf("2\n");
av_init_packet(&packet);
int frameFinished;
int videoFrameCount=0,audioFrameCount=0;
int got_packet,frames=0;
while (av_read_frame(pFormatCtxIn, &packet)>=0) {// 只要有帧 就读到packet中
printf("video frame %d audio frame %d dts-%lld pts-%lld \n",videoFrameCount,audioFrameCount,packet.dts,packet.pts);
frames ++;
/*decodec and codec*/
if (packet.stream_index == videoStream)
{
ret = avcodec_decode_video2(pVideoCodecCtxIn, pFrameIn, &frameFinished, &packet);
videoFrameCount++;
if (frameFinished) {
// pFrameOut->data[0] = pFrameIn->data[0];
// pFrameOut->data[1] = pFrameIn->data[1];
// pFrameOut->data[2] = pFrameIn->data[2];
// pFrameOut->linesize[0] = pFrameIn->linesize[0];
// pFrameOut->linesize[1] = pFrameIn->linesize[1];
// pFrameOut->linesize[2] = pFrameIn->linesize[2];
if (outFmt->flags & AVFMT_RAWPICTURE) { // 不改变图片尺寸
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = video_st->index;
pkt.data = (uint8_t *)pFormatCtxIn;
pkt.size = sizeof(AVPicture);
av_write_frame(pFormatCtxOut, &pkt);
}
else // 需要改变尺寸
{
AVPacket pkt = {0};
av_init_packet(&pkt);
ret = avcodec_encode_video2(pVideoCodecCtxOut, &pkt, pFrameIn, &got_packet);
if (ret<0) {
return;
}
/* If size is zero, it means the image was buffered. */
if (!ret && got_packet && pkt.size) {
printf("frame dts-%lld pts-%lld \n",packet.dts,packet.pts);
pkt.stream_index = video_st->index;
pkt.pts = pVideoCodecCtxOut->coded_frame->pts;
if(pVideoCodecCtxOut->coded_frame->key_frame) // 如果是关键帧
pkt.flags |= AV_PKT_FLAG_KEY;
/* Write the compressed frame to the media file. */
// ret = av_interleaved_write_frame(pFormatCtxOut, &pkt);
av_write_frame(pFormatCtxOut, &pkt);
} else {
ret = 0;
}
}
}
}
else if(packet.stream_index == audioStream)
{
audioFrameCount ++;
printf("frame dts-%lld pts-%lld \n",packet.dts,packet.pts);
av_write_frame(pFormatCtxOut, &packet);
}
// /* get the delayed frames */
// for (got_packet = 1; got_packet; i++) { // got_output ’ê
// fflush(stdout);
// ret = avcodec_encode_video2(pVideoCodecCtxOut, &packet, NULL, &got_packet);
// if (ret < 0) {
// fprintf(stderr, "Error encoding frame\n");
// exit(1);
// }
// if (got_packet) {
// printf("Write frame %3d (size=%5d)\n", i, packet.size);
// av_write_frame(pFormatCtxOut, &packet);
// }
// }
}
av_write_trailer(pFormatCtxOut);
avcodec_close(pVideoCodecCtxIn);
avcodec_close(pVideoCodecCtxOut);
avcodec_close(pAudioCodecCtxIn);
avcodec_close(pAudioCodecCtxOut);
}