编译ffmpeg(第一次),实现JPG转MP4
ffpmeg网址:http://ffmpeg.org/
ffmpegapi文档:http://ffmpeg.org/doxygen/trunk/index.html
因为这是JPG转MP4,所以不涉及音频部分,可参考例子解码:http://ffmpeg.org/doxygen/trunk/decode_video_8c-example.html 编码:http://ffmpeg.org/doxygen/trunk/encode_video_8c-example.html
一、读取到的JPG图像内容需要解码:
1、打开一个解码器需要的内容
AVCodec* pDecodec; AVCodecContext* pDecodecCtx; AVFrame* pDeFrame; AVPacket pDePacket; //读取jpg用的解码器mjpeg pDecodec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); //获取解码器上下文 pDecodecCtx = avcodec_alloc_context3(pDecodec); pDecodecCtx->width = 512; pDecodecCtx->height = 512; pDecodecCtx->pix_fmt = AV_PIX_FMT_RGB24; //打开解码器 avcodec_open2(pDecodecCtx,pDecodec,NULL);
2、解码操作
//用一个avstream来接收解码的数据帧 pDeFrame = av_frame_alloc(); //初始化一个ffmpeg的数据包 av_init_packet(&pDePacket); unsigned char *jpgdata = new unsigned char[2048*2048]; FILE *file; file = fopen([需要打开的文件全路径], "rw"); int readlen = fread(jpgdata, 1, 2048*2048, file); //调用解码器解码 avcodec_decode_video2(pDecodecCtx,pDeFrame,&deCFflag,&pDePacket);
二、创建打开编码器
AVCodec* pEncodec; AVCodecContext* pEncodecCtx; AVFrame* pEnFrame; AVPacket pEnPacket; pEncodecCtx = pVideoStream->codec; pEncodecCtx->codec_id = pOutPutFormatCtx->oformat->video_codec; pEncodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pEncodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; pEncodecCtx->width = 720; pEncodecCtx->height = 576; //pEncodecCtx->bit_rate = 400000; 码流 适用于网络传输 pEncodecCtx->gop_size = 1; pEncodecCtx->time_base.num = 1; pEncodecCtx->time_base.den = 25; pEncodecCtx->qmin = 10; pEncodecCtx->qmax = 51; pEncodecCtx->max_b_frames=3; //质量 文件 pEncodecCtx->bit_rate = 0; av_opt_set_int(pEncodecCtx->priv_data,"crf",0,0); //在文件头写入文件信息(默认在每个包写入文件信息,微软默认播放器可能播放不了) pEncodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //找一个视频编码器 pEncodec = avcodec_find_encoder(pEncodecCtx->codec_id); //打开编码器 avcodec_open2(pEncodecCtx,pEncodec,NULL); int picture_size =0; uint8_t* picture_buf;
//初始换编码用avframe pEnFrame = av_frame_alloc();
//编码的图像大小 picture_size = avpicture_get_size(pEncodecCtx->pix_fmt,pEncodecCtx->width,pEncodecCtx->height);
//编码图像buf picture_buf = (uint8_t *)av_malloc(picture_size);
//关联相关属性 avpicture_fill((AVPicture *)pEnFrame,picture_buf, pEncodecCtx->pix_fmt,pEncodecCtx->width,pEncodecCtx->height); pEnFrame->width = pEncodecCtx->width; pEnFrame->height = pEncodecCtx->height; pEnFrame->format = pEncodecCtx->pix_fmt;
//初始话编码的包 av_init_packet(&pEnPacket);
三、输出文件的信息
AVFormatContext* pOutPutFormatCtx; AVStream* pVideoStream; avformat_alloc_output_context2(&pOutPutFormatCtx, NULL, NULL, [输出的文件全路径].c_str()); pVideoStream = avformat_new_stream(pOutPutFormatCtx, NULL); avio_open(&pOutPutFormatCtx->pb,[输出的文件全路径],AVIO_FLAG_READ_WRITE);
av_dump_format(pOutPutFormatCtx,0,[输出的文件全路径],1);
//将编码器的信息与输出的信息属性关联起来
avcodec_parameters_from_context(pVideoStream->codecpar,pEncodecCtx);
av_codec_get_tag2(pOutPutFormatCtx->oformat->codec_tag, pEncodecCtx->codec_id, &pVideoStream->codecpar->codec_tag);
//写输出的文件的头
avformat_write_header(pOutPutFormatCtx,NULL);
四、转码,将用解码器打开的jpg文件转码成需要编码的Frame格式
//FFmpeg的一个转换类 SwsContext* pImagectx; pImagectx = sws_getContext(pDecodecCtx->width, pDecodecCtx->height, pDecodecCtx->pix_fmt,pEncodecCtx->width,pEncodecCtx->height, pEncodecCtx->pix_fmt,SWS_BICUBIC, NULL,NULL, NULL); sws_scale(pImagectx,pDeFrame->data,pDeFrame->linesize,0,pDeFrame->height,pEnFrame->data,pEnFrame->linesize);
五、编码写文件
注释信息为测试读取文件的逻辑
//snprintf(imagename, 255, "%d.jpg", i);//X.jpg //string imagefilePath = dir + imagename; //printf("---"); //printf(imagefilePath.c_str()); //printf("\n"); //FILE *file; //file = fopen(imagefilePath.c_str(), "rw"); //int readlen = fread(jpgdata, 1, 2048*2048, file); //printf("----read file success %d \n",readlen); //fclose(file); //pDePacket.data = jpgdata; //pDePacket.size = readlen; //int decodecresult = avcodec_decode_video2(pDecodecCtx,pDeFrame,&deCFflag,&pDePacket); //printf("----decodecresult %d \n",decodecresult); //sws_scale(pImagectx,pDeFrame->data,pDeFrame->linesize,0,pDeFrame->height,pEnFrame->data,pEnFrame->linesize); int gotpicture = 0; pEnFrame->pts = i;
//编码
avcodec_encode_video2(pEncodecCtx,&pEnPacket,pEnFrame,&gotpicture); //printf("----encodecresult %d \n",gotpicture); pEnPacket.pts = av_rescale_q(pEnPacket.pts, rational, pVideoStream->time_base); pEnPacket.stream_index = pVideoStream->index;
//将编码得到的包写入输出文件 av_write_frame(pOutPutFormatCtx,&pEnPacket);
//写文件尾
av_write_trailer(pOutPutFormatCtx);
六、释放资源
av_free_packet(&pDePacket); if(pDeFrame != NULL) { av_free(pDeFrame); } if(pDecodecCtx != NULL) { avcodec_close(pDecodecCtx); } av_free_packet(&pEnPacket); if(pEnFrame != NULL) { av_free(pEnFrame); } if(pEncodecCtx != NULL) { avcodec_close(pEncodecCtx); } if(pOutPutFormatCtx!= NULL) { avformat_free_context(pOutPutFormatCtx); } if(pVideoStream != NULL) { av_free(pVideoStream); } if(pImagectx != NULL) { sws_freeContext(pImagectx); }