找到含有I帧的pes后就可以对其进行解码,对I帧的解码我们使用ffmpeg,这里用到的版本是3.0.0。
一、pes解码为yuv,ffmpeg一般都是这个套路,直接上代码:
int ffdecode_pes(uint8_t *pes_data, int32_t pes_size, ffbuffer_t *ffbuffer, char *out_file)
{
int ret = 0;
AVPacket packet;
AVCodec *codec = NULL;
AVCodecContext *codec_ctx = NULL;
AVFrame *frame = NULL;
int got_picture = 0;
if (NULL != out_file) {
write_pes_file(pes_data, pes_size, out_file);
}
avcodec_register_all();
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
codec_ctx = avcodec_alloc_context3(codec);
ret = avcodec_open2(codec_ctx, codec, NULL);
av_init_packet(&packet);
packet.data = NULL;
packet.size = 0;
frame = av_frame_alloc();
packet.size = pes_size;
packet.data = pes_data;
while (1) {
ret = avcodec_decode_video2(codec_ctx, frame, &got_picture, (const AVPacket *)&packet);
if (got_picture) {
frame->format = codec_ctx->pix_fmt;
ffdecode_rgb(frame, ffbuffer);
if (NULL != out_file) {
write_yuv_file(frame , out_file);
write_rgb_file(ffbuffer, out_file);
write_bmp_file(ffbuffer, out_file);
}
break;
}
av_packet_unref(&packet);
}
av_packet_unref(&packet);
av_frame_free(&frame);
avcodec_close(codec_ctx);
avcodec_free_context(&codec_ctx);
return ret;
}
二、yuv解码为rbg,同样也是使用ffmpeg提供的api
int ffdecode_rgb(AVFrame *frame_yuv, ffbuffer_t *buffer_rgb)
{
struct SwsContext *sws_ctx = NULL;
AVFrame *frame_rgb = NULL;
int32_t r = 0;
int32_t w = frame_yuv->width;
int32_t h = frame_yuv->height;
frame_rgb = av_frame_alloc();
r = av_image_fill_arrays(frame_rgb->data, frame_rgb->linesize, \
buffer_rgb->data, buffer_rgb->format, w, h, 1);
sws_ctx = sws_getContext(w, h, frame_yuv->format, \
w, h, AV_PIX_FMT_BGR24, SWS_FAST_BILINEAR, 0, 0, 0);
if (sws_ctx == NULL) {
print_err("sws_getContext() failed. \n");
return -1;
}
r = sws_scale(sws_ctx, (const uint8_t* const*)frame_yuv->data, frame_yuv->linesize, 0, h, frame_rgb->data, frame_rgb->linesize);
av_frame_free(&frame_rgb);
sws_freeContext(sws_ctx);
return r;
}
三、yuv保存为文件
这里保存的是yuv 4:2:0 planer格式,逐行写入,uv分量各占y分量的4分之一。
保存的文件可以用yuv播放器进行播放。
static int write_yuv_file(AVFrame *frame, char *out_file)
{
FILE *fd = NULL;
int i = 0;
char file_name[64];
memset(file_name, 0x00, sizeof(char)*64);
snprintf(file_name, 64, "%s.yuv", out_file);
fd = fopen(file_name, "wb");
/*yuv 4:2:0 planer*/
/*write y*/
for (i = 0; i<frame->height; i++) {
fwrite(frame->data[0]+i*frame->linesize[0], 1, frame->width , fd);
}
/*write u*/
for (i = 0; i<(frame->height/2); i++) {
fwrite(frame->data[1]+i*frame->linesize[1], 1, frame->width/2, fd);
}
/*write v*/
for (i = 0; i<(frame->height/2); i++) {
fwrite(frame->data[2]+i*frame->linesize[2], 1, frame->width/2, fd);
}
fclose(fd);
print_log("%s\n", file_name);
return 0;
}
四、rgb保存为bmp文件
bmp实际就是位图头+rgb数据,需要说明就是高度可能为负数。
可以参考下面这一段解释:
bmp图象的高度,以象素为单位。
这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。
如果该值是一个正数,说明图像是倒向的,即:数据的第一行其实是图像的最后一行,
如果该值是一个负数,则说明图像是正向的。
大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数
代码如下:
static int write_bmp_file(ffbuffer_t *buffer_rgb, char *out_file)
{
bitmap_info_header_t biheader;
bitmap_file_header_t bfheader;
char file_name[64];
FILE* pd = NULL;
int r = 0;
biheader.bi_size = sizeof(bitmap_info_header_t);
biheader.bi_width = buffer_rgb->width;
biheader.bi_height = buffer_rgb->height*(-1);
biheader.bi_planes = 1;
biheader.bi_bit_count = 24;
biheader.bi_compression = 0;
biheader.bi_size_image = 0;
biheader.bi_xpels_per_meter = 0;
biheader.bi_ypels_per_meter = 0;
biheader.bi_clr_used = 0;
biheader.bi_clr_important = 0;
bfheader.bf_type = 0x4d42;
bfheader.bf_size = sizeof(bitmap_file_header_t) + sizeof(bitmap_info_header_t) + buffer_rgb->size;
bfheader.bf_reserved1 = 0;
bfheader.bf_reserved2 = 0;
bfheader.bf_off_bits = sizeof(bitmap_file_header_t) + sizeof(bitmap_info_header_t);
memset(file_name, 0x00, sizeof(char)*64);
snprintf(file_name, 64, "%s.bmp", out_file);
pd = fopen(file_name, "wb");
r = fwrite(&bfheader.bf_type , sizeof(uint16_t), 1, pd);
r = fwrite(&bfheader+sizeof(uint16_t), sizeof(bfheader)-sizeof(uint16_t), 1, pd);
r = fwrite(&biheader , sizeof(biheader), 1, pd);
r = fwrite(buffer_rgb->data , buffer_rgb->size, 1, pd);
fclose(pd);
print_log("%s\n", file_name);
return r;
}
mpeg2标准:https://download.csdn.net/download/maxzero/10402761
完整的代码:https://download.csdn.net/download/maxzero/10572383