2012-11-26 69 views
4

當我解碼avi文件中的幀,然後在x264中解碼並保存到mp4文件時,輸出文件的fps始終爲12800。因此該文件播放速度非常快。但是,當我以avi格式保存h264幀中的編碼而不是mp4時,所以fps是我想要的 - 25.在mp4容器中保存視頻時FPS過高

可能是什麼問題?

下面的代碼我在VS2010中寫道:

#include "stdafx.h" 
#include "inttypes.h" 

extern "C" { 
#include "libavcodec/avcodec.h" 
#include "libavformat/avformat.h" 
#include "libavutil/avutil.h" 
#include <libswscale/swscale.h> 
#include <libavutil/opt.h> 
#include <libswscale/swscale.h> 
#include <libavutil/imgutils.h> 
} 

#include <iostream> 
using namespace std; 

int main(int argc, char* argv[]) 
{ 
    const char* inFileName = "C:\\000227_C1_GAME.avi"; 
    const char* outFileName = "c:\\test.avi"; 
    const char* outFileType = "avi"; 

    av_register_all(); 

    AVFormatContext* inContainer = NULL; 
    if(avformat_open_input(&inContainer, inFileName, NULL, NULL) < 0) 
     exit(1); 

    if(avformat_find_stream_info(inContainer, NULL) < 0) 
     exit(1); 

    // Find video stream 
    int videoStreamIndex = -1; 
    for (unsigned int i = 0; i < inContainer->nb_streams; ++i) 
    { 
     if (inContainer->streams[i] && inContainer->streams[i]->codec && 
     inContainer->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
     { 
     videoStreamIndex = i; 
     break; 
     } 
    } 
    if (videoStreamIndex == -1) exit(1); 

    AVFormatContext* outContainer = NULL; 
    if(avformat_alloc_output_context2(&outContainer, NULL, outFileType, outFileName) < 0) 
     exit(1); 

    // ---------------------------- 
    // Decoder 
    // ---------------------------- 
    AVStream const *const inStream = inContainer->streams[videoStreamIndex]; 
    AVCodec *const decoder = avcodec_find_decoder(inStream->codec->codec_id); 
    if(!decoder) 
     exit(1); 
    if(avcodec_open2(inStream->codec, decoder, NULL) < 0) 
     exit(1); 

    // ---------------------------- 
    // Encoder 
    // ----------------------------    
    AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264); 
    if(!encoder) 
     exit(1); 
    AVStream *outStream = avformat_new_stream(outContainer, encoder);  
    if(!outStream) 
     exit(1); 
    avcodec_get_context_defaults3(outStream->codec, encoder); 

    // Construct encoder 
    if(outContainer->oformat->flags & AVFMT_GLOBALHEADER) 
     outStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 

    outStream->codec->coder_type = AVMEDIA_TYPE_VIDEO; 
    outStream->codec->pix_fmt = AV_PIX_FMT_YUV420P; 
    outStream->codec->width = inStream->codec->width; 
    outStream->codec->height = inStream->codec->height; 
    outStream->codec->codec_id = encoder->id; 
    outStream->codec->bit_rate = 500000; 
    //outStream->codec->rc_min_rate = 600000; 
    //outStream->codec->rc_max_rate = 800000; 

    outStream->codec->time_base.den = 25; 
    outStream->codec->time_base.num = 1; 
    outStream->codec->gop_size = 250; // Keyframe interval(=GOP length). Determines maximum distance distance between I-frames 
    outStream->codec->keyint_min = 25; // minimum GOP size 
    outStream->codec->max_b_frames = 3;//16; // maximum number of B-frames between non-B-frames 
    outStream->codec->b_frame_strategy = 1; // decides the best number of B-frames to use. Default mode in x264. 
    outStream->codec->scenechange_threshold = 40; 
    outStream->codec->refs = 6; // abillity to reference frames other than the one immediately prior to the current frame. specify how many references can be used. 
    outStream->codec->qmin = 0;//10; 
    outStream->codec->qmax = 69;//51; 
    outStream->codec->qcompress = 0.6; 
    outStream->codec->max_qdiff = 4; 
    outStream->codec->i_quant_factor = 1.4;//0.71; 

    outStream->codec->refs=1;//3; 
    outStream->codec->chromaoffset = -2; 
    outStream->codec->thread_count = 1; 
    outStream->codec->trellis = 1; 
    outStream->codec->me_range = 16; 
    outStream->codec->me_method = ME_HEX; //hex 
    outStream->codec->flags2 |= CODEC_FLAG2_FAST; 
    outStream->codec->coder_type = 1; 


    if(outStream->codec->codec_id == AV_CODEC_ID_H264) 
    { 
     av_opt_set(outStream->codec->priv_data, "preset", "slow", 0); 
    } 

    // Open encoder 
    if(avcodec_open2(outStream->codec, encoder, NULL) < 0) 
     exit(1); 

    // Open output container 
    if(avio_open(&outContainer->pb, outFileName, AVIO_FLAG_WRITE) < 0) 
     exit(1); 

    //close_o 

    AVFrame *decodedFrame = avcodec_alloc_frame(); 
    if(!decodedFrame) 
     exit(1); 
    AVFrame *encodeFrame = avcodec_alloc_frame(); 
    if(!encodeFrame) 
     exit(1); 
    encodeFrame->format = outStream->codec->pix_fmt; 
    encodeFrame->width = outStream->codec->width; 
    encodeFrame->height = outStream->codec->height; 
    if(av_image_alloc(encodeFrame->data, encodeFrame->linesize, 
       outStream->codec->width, outStream->codec->height, 
       outStream->codec->pix_fmt, 1) < 0) 
     exit(1); 

    av_dump_format(inContainer, 0, inFileName,0); 

    //Write header to ouput container 
    avformat_write_header(outContainer, NULL); 

    AVPacket decodePacket, encodedPacket; 
    int got_frame, len; 
    while(av_read_frame(inContainer, &decodePacket)>=0) 
    {  
     if (decodePacket.stream_index == videoStreamIndex) 
     {     
     len = avcodec_decode_video2(inStream->codec, decodedFrame, &got_frame, &decodePacket); 
     if(len < 0) 
      exit(1); 
     if(got_frame) 
     { 
      av_init_packet(&encodedPacket); 
      encodedPacket.data = NULL; 
      encodedPacket.size = 0;   
      if(avcodec_encode_video2(outStream->codec, &encodedPacket, decodedFrame, &got_frame) < 0) 
       exit(1); 
      if(got_frame) 
      { 
       if (outStream->codec->coded_frame->key_frame) 
        encodedPacket.flags |= AV_PKT_FLAG_KEY; 

       encodedPacket.stream_index = outStream->index; 

       if(av_interleaved_write_frame(outContainer, &encodedPacket) < 0) 
        exit(1); 

       av_free_packet(&encodedPacket); 
      } 
     } 
     } 

     av_free_packet(&decodePacket); 
    } 
    av_write_trailer(outContainer); 
    avio_close(outContainer->pb); 

    avcodec_free_frame(&encodeFrame); 
    avcodec_free_frame(&decodedFrame); 

    avformat_free_context(outContainer); 
    av_close_input_file(inContainer); 
    return 0; 
} 
+0

有沒有人可以幫助我? – theateist

回答

7

的問題是與PTS和數據包的DTS。在寫入數據包到輸出之前(在av_interleaved_write_frame命令之前)設置PTS和DTS像這樣

if (encodedPacket.pts != AV_NOPTS_VALUE) 
    encodedPacket.pts = av_rescale_q(encodedPacket.pts, outStream->codec->time_base, outStream->time_base); 
if (encodedPacket.dts != AV_NOPTS_VALUE) 
    encodedPacket.dts = av_rescale_q(encodedPacket.dts, outStream->codec->time_base, outStream->time_base);