2 sjustfly sjustfly 于 2013.08.20 17:55 提问

在用ffmpeg 2.0做一个转码工具的时候,转出的视频 视频播放速度变快

在用最新版 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);

}

1个回答

czhc520
czhc520   2013.09.17 15:07

你现在有解决这个问题吗?我也碰到了。77848041,+我,交流

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!