ffmpeg-封装格式转换 YUV转h264/h265 MP4转AVI

源自ffmpeg实战教程(三)音频PCM采样为AAC,视频YUV编码为H264/HEVC

1、没有使用AVFormatContext
2、一帧图像的Y U V 独立读取,独立编码,独立写入?

关键代码:

#if TEST_HEVC
    AVCodecID codec_id=AV_CODEC_ID_HEVC;
    char filename_out[]="ws.hevc";
#else
    AVCodecID codec_id=AV_CODEC_ID_H264;
    char filename_out[]="ws.h264";
#endif

int framenum=100;
//没有使用AVFormate
avcodec_register_all();
pCodec = avcodec_find_encoder(codec_id);
pCodecCtx = avcodec_alloc_context3(pCodec);
pCodecCtx->bit_rate = 400000;
	pCodecCtx->width = 480;
	pCodecCtx->height = 272;
	pCodecCtx->time_base.num=1;
	pCodecCtx->time_base.den=25;
	pCodecCtx->gop_size = 10;
	pCodecCtx->max_b_frames = 1;
	pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec_id == AV_CODEC_ID_H264)	av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);
avcodec_open2(pCodecCtx, pCodec, NULL)

pFrame = av_frame_alloc();
	pFrame->format = pCodecCtx->pix_fmt;
	pFrame->width  = pCodecCtx->width;
	pFrame->height = pCodecCtx->height;
av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, 16);


#Encode
y_size = pCodecCtx->width * pCodecCtx->height;
for (i = 0; i < framenum; i++) {
    av_init_packet(&pkt);
    pkt.data = NULL;    // packet data will be allocated by the encoder
    pkt.size = 0;
    //Read raw YUV data
    if (fread(pFrame->data[0],1,y_size,fp_in)<= 0||     // Y 	|| 前面为真则忽略后面 前面为假则判断后面
        fread(pFrame->data[1],1,y_size/4,fp_in)<= 0||   // U
        fread(pFrame->data[2],1,y_size/4,fp_in)<= 0){   // V
        return -1;
    }else if(feof(fp_in)){
        break;
    }
    
#encode the image
    pFrame->pts = i;
    /* encode the image */
    avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);
    if (got_output) {
        printf("Succeed to encode frame: %5d\tsize:%5d\n",framecnt,pkt.size);
        framecnt++;
        fwrite(pkt.data, 1, pkt.size, fp_out);
        av_free_packet(&pkt);
    }

#Flush Encoder
for (got_output = 1; got_output; i++) {
    avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
    if (got_output) {
        printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",pkt.size);
        fwrite(pkt.data, 1, pkt.size, fp_out);
        av_free_packet(&pkt);
    }
}

MP4转AVI

1、音频压缩码流从一种封装格式文件中获取出来然后打包成另外一种封装格式的文件
2、不需要进行视音频的编码和解码
3.、思路:程序包含了对两个文件的处理:读取输入文件和写入输出文件。然后使用了一个avcodec_copy_context()拷贝输入的AVCodecContext到输出的AVCodecContext。然后再从输出的AVCodecContext写进输出文件

int main(int argc, char* argv[])
{
    AVOutputFormat *ofmt = NULL;
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    const char *in_filename, *out_filename;
    int ret, i;
    int frame_index=0;
    in_filename  = "ws.mp4";//Input file URL
    out_filename = "ws.avi";//Output file URL
    av_register_all();
	
#Input
    avformat_open_input(&ifmt_ctx, in_filename, 0, 0);
    avformat_find_stream_info(ifmt_ctx, 0);
	
#Output
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
    ofmt = ofmt_ctx->oformat;
    for (i = 0; i < ifmt_ctx->nb_streams; i++) {
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);// 初始化AVStream 

        //关键:Copy the settings of AVCodecContext
        avcodec_copy_context(out_stream->codec, in_stream->codec);

        out_stream->codec->codec_tag = 0;
        if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
            out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }
    
#Open output file
    if (!(ofmt->flags & AVFMT_NOFILE)) {
        avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
    }

    avformat_write_header(ofmt_ctx, NULL)#Encode
    while (1) {
        AVStream *in_stream, *out_stream;
        av_read_frame(ifmt_ctx, &pkt);
        in_stream  = ifmt_ctx->streams[pkt.stream_index];
        out_stream = ofmt_ctx->streams[pkt.stream_index];
 
        //Convert PTS/DTS
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;

        av_interleaved_write_frame(ofmt_ctx, &pkt);

        printf("Write %8d frames to output file\n",frame_index);
        av_free_packet(&pkt);
        frame_index++;
    }
    av_write_trailer(ofmt_ctx);
	
end:
    avformat_close_input(&ifmt_ctx);
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))  avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
    
    return 0;
}
发布了81 篇原创文章 · 获赞 1 · 访问量 2914

猜你喜欢

转载自blog.csdn.net/qq_42024067/article/details/103867803