代码截取自FFMPEG官方example,添加注释以FFMPEG的编码流程就变得很清楚了
static void video_encode_example(const char *filename, int codec_id) { //1.定义如下数据结构 AVCodec *codec; AVCodecContext *c= NULL; int i, ret, x, y, got_output; FILE *f; AVFrame *frame; AVPacket pkt; uint8_t endcode[] = { 0, 0, 1, 0xb7 };//MPEG文件尾 printf("Encode video file %s\n", filename); /* find the mpeg1 video encoder */ codec = avcodec_find_encoder(codec_id); //2.查找编码器 if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } c = avcodec_alloc_context3(codec); //3.分配编码器结构体 if (!c) { fprintf(stderr, "Could not allocate video codec context\n"); exit(1); } /* put sample parameters */ //4.设置编码器参数 c->bit_rate = 400000; /* resolution must be a multiple of two */ c->width = 352; c->height = 288; /* frames per second */ c->time_base= (AVRational){1,25}; c->gop_size = 10; /* emit one intra frame every ten frames */ c->max_b_frames=1; c->pix_fmt = AV_PIX_FMT_YUV420P; if(codec_id == AV_CODEC_ID_H264) av_opt_set(c->priv_data, "preset", "slow", 0); /* open it */ if (avcodec_open2(c, codec, NULL) < 0) { //5.打开编码器 fprintf(stderr, "Could not open codec\n"); exit(1); } f = fopen(filename, "wb"); //6.打开文件 if (!f) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } frame = avcodec_alloc_frame(); //7.分配帧结构体 if (!frame) { fprintf(stderr, "Could not allocate video frame\n"); exit(1); } frame->format = c->pix_fmt; frame->width = c->width; frame->height = c->height; /* the image can be allocated by any means and av_image_alloc() is * just the most convenient way if av_malloc() is to be used */ //8.分配帧数据空间frame->data, ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32); if (ret < 0) { fprintf(stderr, "Could not allocate raw picture buffer\n"); exit(1); } /* encode 1 second of video */ for(i=0;i<25;i++) { av_init_packet(&pkt); //9.初始化 packet 结构体,packet数据由编码器分配 pkt.data = NULL; // packet data will be allocated by the encoder pkt.size = 0; fflush(stdout); /* prepare a dummy image */ /* Y */ //10.设定帧数据 for(y=0;y<c->height;y++) { for(x=0;x<c->width;x++) { frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3; } } /* Cb and Cr */ for(y=0;y<c->height/2;y++) { for(x=0;x<c->width/2;x++) { frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2; frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5; } } frame->pts = i; /* encode the image */ //11.编码一帧数据到 packet 中 ret = avcodec_encode_video2(c, &pkt, frame, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame\n"); exit(1); } if (got_output) { printf("Write frame %3d (size=%5d)\n", i, pkt.size); fwrite(pkt.data, 1, pkt.size, f); av_free_packet(&pkt); } } /* get the delayed frames */ //12.编码延迟帧,avcodec_encode_video2()中 frame参数置为NULL for (got_output = 1; got_output; i++) { fflush(stdout); ret = avcodec_encode_video2(c, &pkt, NULL, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame\n"); exit(1); } if (got_output) { printf("Write frame %3d (size=%5d)\n", i, pkt.size); fwrite(pkt.data, 1, pkt.size, f); av_free_packet(&pkt); //13.释放 packet } } /* add sequence end code to have a real mpeg file */ fwrite(endcode, 1, sizeof(endcode), f); //14.写入MPEG文件尾,close文件和结构体,释放指针数据 fclose(f); avcodec_close(c); av_free(c); av_freep(&frame->data[0]); avcodec_free_frame(&frame); printf("\n"); }