2012-11-08 31 views
5

ffmpeg kullanmaya başladım ve avi dosyasını mp4/h264 dosyasına dönüştürmek istiyorum. this dahil olmak üzere pek çok gönderi okudum, ancak mp4 dosyasına kareleri nasıl kaydedeceğimi iyi bir örnek bulamadım. Aşağıdaki kod, avi dosyalarından çerçeveleri çözen ve H264/mp4 dosyasına kodlayan basitleştirilmiş, ancak kareleri kaydettiğimde mp4 dosyası oynatılamıyor. Neyin yanlış olduğunu ve nasıl düzeltileceğini söyleyebilmen için minnettar olacağım,Çerçeveler avi kapsayıcıdan kod çözme ve bunları h264/mp4'e kodlama neden çalışmıyor?

.

const char* aviFileName = "aviFrom.avi"; 
const char* mp4FileName = "mp4To.mp4"; 

// Filling pFormatCtx by open video file and Retrieve stream information 
// ... 
// Retrieving codecCtxDecode and opening codecDecode 
//... 


// Get encoder 
codecCtxEncode = avcodec_alloc_context(); 
codecCtxEncode->qmax = 69; 
codecCtxEncode->max_qdiff = 4; 
codecCtxEncode->bit_rate = 400000; 
codecCtxEncode->width = codecCtxDecode->width; 
codecCtxEncode->height = codecCtxDecode->height; 
codecCtxEncode->pix_fmt = AV_PIX_FMT_YUV420P; 
codecEncode = avcodec_find_encoder(CODEC_ID_H264); 
if(codecEncode == NULL) 
    return -1; 
if(avcodec_open2(codecCtxEncode, codecEncode, NULL)) 
    return -1; 

SwsContext *sws_ctx = sws_getContext(codecCtxDecode->width, codecCtxDecode->height, codecCtxDecode->pix_fmt, 
          codecCtxDecode->width, codecCtxDecode->height, AV_PIX_FMT_YUV420P, 
          SWS_BILINEAR, NULL, NULL, NULL); 

// Allocate an AVFrame structure  
frameDecoded = avcodec_alloc_frame(); 
frameEncoded = avcodec_alloc_frame();  

avpicture_alloc((AVPicture *)frameEncoded, AV_PIX_FMT_YUV420P, codecCtxDecode->width, codecCtxDecode->height); 

while(av_read_frame(pFormatCtx, &packet)>=0) 
{  
    // Is this a packet from the video stream? 
    if(packet.stream_index==videoStreamIndex) { 
     avcodec_decode_video2(codecCtxDecode, frameDecoded, &frameFinished, &packet); 
     // Did we get a video frame? 
     if(frameFinished) 
     {   
      fwrite(packet.data, packet.size, 
      sws_scale(sws_ctx, frameDecoded->data, frameDecoded->linesize, 0, codecCtxDecode->height, 
         frameEncoded->data, frameEncoded->linesize); 



      int64_t pts = packet.pts; 
      av_free_packet(&packet); 
      av_init_packet(&packet); 
      packet.data = NULL; 
      packet.size = 0;  
      frameEncoded->pts = pts;     

      int failed = avcodec_encode_video2(codecCtxEncode, &packet, frameEncoded, &got_output); 
      if(failed) 
      { 
       exit(1); 
      } 
      fwrite(packet.data,1,packet.size, mp4File); 
     } 
    } 

    av_free_packet(&packet); 
} 

cevap

8

Doğrudan ham paketler yazmak yerine ffmpeg çıktı bağlamını kullanmanız gerekir.

// find output format 
AVOutputFormat * outputFormat = av_guess_format("mp4", NULL, NULL); 
AVFormatContext *outFmtCtx = NULL; 

// create output cotext 
avformat_alloc_output_context2(&outFmtCtx, outputFormat, NULL, NULL); 

// create new stream 
AVStream * outStrm = avformat_new_stream(outFmtCtx, codecEncode); 
avcodec_get_context_defaults3(outStrm->codec, *codec); 

outStrm->codec->codec_id = codec_id; 
outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO; 
/// outStrm->codec-> ... 
/// set all fields marked as "MUST be set by user" in avcodec.h 
/// .... 

// create file 
avio_open2(&outFmtCtx->pb, file_name, AVIO_FLAG_WRITE, NULL, NULL); 
avformat_write_header(outFmtCtx, NULL); 

/// write packets 
/// for () 
av_interleaved_write_frame(outFmtCtx, packet); 

/// finish 
av_write_trailer(outFmtCtx); 
avio_close(outFmtCtx->pb); 
avformat_free_context(outFmtCtx); 

UPD: tam kod bu yeniden kodlama olmadan kopya videoyu:

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

int main(int argc, char* argv[]) 
{ 
    const char * kInputFileName = "f:/Projects/Temp/testFFMPEG2/test/test_in.avi"; 
    const char * kOutputFileName = "f:/Projects/Temp/testFFMPEG2/test/text_out.avi"; 
    const char * kOutputFileType = "avi"; 

    av_register_all(); 

    AVFormatContext * inCtx = NULL; 
    int err = avformat_open_input(&inCtx, kInputFileName, NULL, NULL); 
    if (err < 0) 
     exit(1); 

    err = av_find_stream_info(inCtx); 
    if (err < 0) 
     exit(1); 


    int vs = -1; 
    for (unsigned int s = 0; s < inCtx->nb_streams; ++s) 
    { 
     if (inCtx->streams[s] && 
      inCtx->streams[s]->codec && 
      inCtx->streams[s]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
     { 
      vs = s; 
      break; 
     }   
    } 

    if (vs == -1) 
     exit(1); 

    AVOutputFormat * outFmt = av_guess_format(kOutputFileType, NULL, NULL); 
    if (!outFmt) 
     exit(1); 

    AVFormatContext *outCtx = NULL; 
    err = avformat_alloc_output_context2(&outCtx, outFmt, NULL, NULL); 

    if (err < 0 || !outCtx) 
     exit(1); 

    AVStream * outStrm = av_new_stream(outCtx, 0); 
    AVStream const * const inStrm = inCtx->streams[vs]; 
    AVCodec * codec = NULL; 
    avcodec_get_context_defaults3(outStrm->codec, codec); 
    outStrm->codec->thread_count = 1; 

#if (LIBAVFORMAT_VERSION_MAJOR == 53) 
    outStrm->stream_copy = 1; 
#endif 

    outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO; 
    if(outCtx->oformat->flags & AVFMT_GLOBALHEADER) 
     outStrm->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 

    outStrm->codec->sample_aspect_ratio = outStrm->sample_aspect_ratio = inStrm->sample_aspect_ratio; 

#if (LIBAVFORMAT_VERSION_MAJOR == 53) 
    outCtx->timestamp = 0; 
#endif 

    err = avio_open(&outCtx->pb, kOutputFileName, AVIO_FLAG_WRITE); 
    if (err < 0) 
     exit(1); 

#if (LIBAVFORMAT_VERSION_MAJOR == 53) 
    AVFormatParameters params = {0}; 
    err = av_set_parameters(outCtx, &params); 
    if (err < 0) 
     exit(1); 
#endif 

    outStrm->disposition = inStrm->disposition; 
    outStrm->codec->bits_per_raw_sample = inStrm->codec->bits_per_raw_sample; 
    outStrm->codec->chroma_sample_location = inStrm->codec->chroma_sample_location; 
    outStrm->codec->codec_id = inStrm->codec->codec_id; 
    outStrm->codec->codec_type = inStrm->codec->codec_type; 

    if (!outStrm->codec->codec_tag) 
    { 
     if (! outCtx->oformat->codec_tag 
      || av_codec_get_id (outCtx->oformat->codec_tag, inStrm->codec->codec_tag) == outStrm->codec->codec_id 
      || av_codec_get_tag(outCtx->oformat->codec_tag, inStrm->codec->codec_id) <= 0) 
        outStrm->codec->codec_tag = inStrm->codec->codec_tag; 
    } 

    outStrm->codec->bit_rate = inStrm->codec->bit_rate; 
    outStrm->codec->rc_max_rate = inStrm->codec->rc_max_rate; 
    outStrm->codec->rc_buffer_size = inStrm->codec->rc_buffer_size; 

    const size_t extra_size_alloc = (inStrm->codec->extradata_size > 0) ? 
            (inStrm->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE) : 
            0; 

    if (extra_size_alloc) 
    { 
     outStrm->codec->extradata = (uint8_t*)av_mallocz(extra_size_alloc);  
     memcpy(outStrm->codec->extradata, inStrm->codec->extradata, inStrm->codec->extradata_size); 
    } 
    outStrm->codec->extradata_size = inStrm->codec->extradata_size; 

    AVRational input_time_base = inStrm->time_base; 
    AVRational frameRate = {25, 1}; 
    if (inStrm->r_frame_rate.num && inStrm->r_frame_rate.den 
     && (1.0 * inStrm->r_frame_rate.num/inStrm->r_frame_rate.den < 1000.0)) 
    { 
     frameRate.num = inStrm->r_frame_rate.num; 
     frameRate.den = inStrm->r_frame_rate.den; 
    } 

    outStrm->r_frame_rate = frameRate; 
    outStrm->codec->time_base = inStrm->codec->time_base; 

    outStrm->codec->pix_fmt = inStrm->codec->pix_fmt; 
    outStrm->codec->width = inStrm->codec->width; 
    outStrm->codec->height = inStrm->codec->height; 
    outStrm->codec->has_b_frames = inStrm->codec->has_b_frames; 
    if (! outStrm->codec->sample_aspect_ratio.num) { 
     AVRational r0 = {0, 1}; 
     outStrm->codec->sample_aspect_ratio = 
      outStrm->sample_aspect_ratio = 
      inStrm->sample_aspect_ratio.num ? inStrm->sample_aspect_ratio : 
      inStrm->codec->sample_aspect_ratio.num ? 
      inStrm->codec->sample_aspect_ratio : r0; 
    } 
#if LIBAVFORMAT_VERSION_MAJOR == 53 
    av_write_header(outFmtCtx); 
#else 
    avformat_write_header(outCtx, NULL); 
#endif 


    for (;;) 
    { 
     AVPacket packet = {0}; 
     av_init_packet(&packet); 

     err = AVERROR(EAGAIN); 
     while (AVERROR(EAGAIN) == err) 
      err = av_read_frame(inCtx, &packet); 

     if (err < 0) 
     { 
      if (AVERROR_EOF != err && AVERROR(EIO) != err) 
      { 
       // error 
       exit(1);    
      } 
      else 
      { 
       // end of file 
       break; 
      }    
     } 


     if (packet.stream_index == vs) 
     { 

      err = av_interleaved_write_frame(outCtx, &packet); 
      if (err < 0) 
       exit(1); 
     }    

     av_free_packet(&packet);   

    } 

    av_write_trailer(outCtx); 
    if (!(outCtx->oformat->flags & AVFMT_NOFILE) && outCtx->pb) 
     avio_close(outCtx->pb); 

    avformat_free_context(outCtx); 
    av_close_input_file(inCtx); 
    return 0; 
} 
+0

varsayımsal olarak, eğer elle olur

temel adımlar gerçekleştirmek için gereken üstbilgi ve altbilgiyi dosyaya ekleyin, tamam mı? – theateist

+0

Bazı formatlar için işe yarayabilir, ancak genelde bu yanlış yoldur. – pogorskiy

+0

yazdıklarınızla denemeye gelince, avi dosyasından okumaya çalıştım ve okuduğum paketlerin (kod çözmeden) yeni avi dosyasına yazılmasını sağladım. Ben aynı dosyayı almayı bekledim ama yeni dosya 3KB daha büyük ve medya oynatıcı açamıyor – theateist