在尝试使用Windows上的x264编码器构建ffmpeg静态库之后经过了相当长的一段时间后,我花了一些时间来编写一些示例。 当然,有很多关于如何构建,如何使用,bla bla的“说明”......但是,它们不适用于Windows。我想Linux家伙在这里处于更好的位置。现在,这个数十亿美元的问题是“这一切的目的是什么?”。不仅这在Windows上没用,而且我本可以买到一些实际可行的第三方库。
如果有人要说“但是,它有效!”。我必须说,给我一个工作证明。我不关心200x100,10fps。我不需要H264。演示如何压缩一秒钟的1080i素材。它是H264,它是跨平台(听起来很有趣,如果你问我),谷歌正在使用它(它必须是完美的,对吗?),更多的是在这里...
答案 0 :(得分: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;
}
答案 1 :(得分:0)
如果要在隔行扫描模式下使用libavcodec + libx264进行编码,请使用CODEC_FLAG_INTERLACED_DCT
。如果可能的话,你应该直接使用libx264或CLI程序,但它的工作量较少。