2011-12-09 54 views
2

在Windows上尝试使用x264编码器构建ffmpeg静态库之后,花了相当长的时间,我花了一些时间用它编写一些示例。 当然,关于如何构建,如何使用,bla bla还有大量的“指令”......但是,它们中没有一个适用于Windows。我猜这些Linux员工在这里处于更好的位置。现在,亿美元的问题是“所有这些的目的是什么?”。不仅如此,这在Windows上是无用的,但我可以购买一些实际工作的第三方库。x264&libavcodec

如果有人要说“但是,它工作!”。我必须说,给我一个工作证明。我不关心在10fps的200x100。我不需要H264。演示如何压缩一秒钟的1080i画面。这是H264,它是跨平台(听起来很有趣,如果你问我),谷歌正在使用它(它必须是完美的,对吧?),在这里更多的hipe ...

回答

3

首先,不要尝试和建立在Windows - 特别是如果你使用VS - 从here

得到它然后,程序是这样的:

// in ctor 
ffmpeg::avcodec_register_all(); 
ffmpeg::avcodec_init(); 
ffmpeg::av_register_all(); 

bool createFile(const String &fileName,unsigned int width,unsigned int height,unsigned int fps) 
{ 

    close(); 

    pFormatCtx=ffmpeg::avformat_alloc_context(); 
    if(!pFormatCtx) 
    { 
     printf("Error allocating format context\n"); 
     return false; 
    } 


    pOutputFormat = ffmpeg::av_guess_format("mp4", filename,NULL); 


    pFormatCtx->oformat = pOutputFormat; 
    _snprintf(pFormatCtx->filename, sizeof(pFormatCtx->filename), "%s",filename); 

    // Add the video stream 
    pVideoStream = av_new_stream(pFormatCtx,0); 
    if(!pVideoStream) 
    { 
     printf("Could not allocate stream\n"); 
     return false; 
    } 


    pCodecCtx=pVideoStream->codec; 
    pCodecCtx->codec_id = pOutputFormat->video_codec; 
    pCodecCtx->codec_type = ffmpeg::AVMEDIA_TYPE_VIDEO; 


    pCodecCtx->width = Width = width; 
    pCodecCtx->height = Height = height;  
    pCodecCtx->time_base.num = 1; 
    pCodecCtx->time_base.den = Fps = fps; 
    pCodecCtx->pix_fmt = ffmpeg::PIX_FMT_YUV420P; 


    // needed for x264 to work 
    pCodecCtx->me_range = 16; 
    pCodecCtx->max_qdiff = 4; 
    pCodecCtx->qmin = 10; 
    pCodecCtx->qmax = 51; 
    pCodecCtx->qcompress = 0.6; 
    pCodecCtx->gop_size = 12; 




    avcodec_thread_init(pCodecCtx, 10); 


    // some formats want stream headers to be separate 
    if(pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER) 
     pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; 


    if (av_set_parameters(pFormatCtx, NULL) < 0) 
    { 
     printf("Invalid output format parameters\n"); 
     return false; 
    } 

    ffmpeg::dump_format(pFormatCtx, 0, pFormatCtx->filename, 1); 

    // open_video 
    // find the video encoder 
    pCodec = avcodec_find_encoder(pCodecCtx->codec_id); 
    if (!pCodec) 
    { 
     printf("codec not found\n"); 
     return false; 
    } 
    // open the codec 
    if (avcodec_open(pCodecCtx, pCodec) < 0) 
    { 
     printf("could not open codec\n"); 
     return false; 
    } 

    // Allocate memory for output 
    if(!initOutputBuf()) 
    { 
     printf("Can't allocate memory for output bitstream\n"); 
     return false; 
    } 

    // Allocate the YUV frame 
    if(!initFrame()) 
    { 
     printf("Can't init frame\n"); 
     return false; 
    } 

    if (url_fopen(&pFormatCtx->pb,pFormatCtx->filename, URL_WRONLY) < 0) 
    { 
     printf("Could not open '%s'\n", pFormatCtx->filename); 
     return false; 
    } 


    av_write_header(pFormatCtx); 

    return true; 
} 

然后,每帧

int encodeImage(const QImage &img) 
{ 

    if (!convertImage_sws(img)) {  // SWS conversion 
     return false; 
    } 


    ppicture->pts=pCodecCtx->frame_number; 

    //memset(outbuf,0,outbuf_size); 
    int out_size = ffmpeg::avcodec_encode_video(pCodecCtx,outbuf,outbuf_size,ppicture); 

    if (out_size > 0) { 
     ffmpeg::AVPacket pkt; 
     av_init_packet(&pkt); 


     if (pCodecCtx->coded_frame->pts != (0x8000000000000000LL)) 
     pkt.pts= av_rescale_q(pCodecCtx->coded_frame->pts, pCodecCtx->time_base, pVideoStream->time_base); 

     if(pCodecCtx->coded_frame->key_frame) 
     pkt.flags |= AV_PKT_FLAG_KEY; 

     pkt.stream_index= pVideoStream->index; 
     pkt.data= outbuf; 
     pkt.size= out_size;  
     if (av_write_frame(pFormatCtx, &pkt) < 0) {   
      return 0; 
     }   
    } 

    return out_size; 
} 

void close() 
{ 

    av_write_trailer(pFormatCtx); 

    // close_video 
    avcodec_close(pVideoStream->codec); 
    freeFrame(); 
    freeOutputBuf(); 


    /* free the streams */ 
    for(int i = 0; i < pFormatCtx->nb_streams; i++) 
    { 
     av_freep(&pFormatCtx->streams[i]->codec); 
     av_freep(&pFormatCtx->streams[i]); 
    } 

    // Close file 
    url_fclose(pFormatCtx->pb); 

    // Free the stream 
    av_free(pFormatCtx); 

} 


bool initFrame() 
{ 
    ppicture = ffmpeg::avcodec_alloc_frame(); 
    if(ppicture==0) 
     return false; 

    int size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); 
    picture_buf = new uint8_t[size]; 
    if(picture_buf==0) 
    { 
     av_free(ppicture); 
     ppicture=0; 
     return false; 
    } 

    // Setup the planes 
    avpicture_fill((ffmpeg::AVPicture *)ppicture, picture_buf,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); 

    ppicture->pts = 0; 
    return true; 
} 
+0

在发布之前,我做了几乎相同的事情。但是,我仍然错过了交错的部分。 x264如何知道它正在压缩隔行帧?而且,我在avcodec_encode_video()之后得到的是关于时间戳的一些警告,并且返回值为零。根据ffmpeg,函数成功,但零字节意味着什么 - 没有。顺便说一下,我需要自己构建静态库,因为每隔一段时间我都会发现一个bug。它总是与Windows相关...至少这是我从源头上可以看出来的。 – moose

+0

顺便说一句,我发现了另一个错误...我试图做你所描述的。也许一些微小的差异很重要... av_guess_format(“mp4”,szFileName,NULL);将以无限循环结束。 :-( – moose

+0

avformat_alloc_output_context2()函数会出现同样的无限循环行为,无论如何,我放弃了...太多的bug。 – moose

0

如果你想ENCOD e在交错模式下使用libavcodec + libx264,使用CODEC_FLAG_INTERLACED_DCT。如果可能的话,你应该直接使用libx264或者CLI程序,但这不是一件容易的事情。