ffmpeg从AVFrame取出yuv数据到保存到char*中
很多人一直不知道怎么利用ffmpeg从AVFrame取出yuv数据到保存到char*中,下面代码将yuv420p和yuv422p的数据取出并保存到char*buf中。
其他格式可以自己去扩展,前提先看戏yuv的各种格式,yuv的各种格式链接:数据格式分析
先确保视频格式sws_getContext()转换后是YUV格式:
1 out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));//分配AVFrame所需内存 2 avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//填充AVFrame 3 4 img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 5 pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
那么在后续的视频数据处理时,可以把YUV视频格式数据进行存储:
1 //如果是视频 2 else if (pstream_info[i].dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) 3 { 4 int new_videosize = pkt.size; 5 int video_decode_size = avpicture_get_size(pstream_info->dec_ctx->pix_fmt, Zoom_Width,Zoom_Height); 6 uint8_t * video_decode_buf =( uint8_t *)calloc(1,video_decode_size * 3 * sizeof(char)); //最大分配的空间,能满足yuv的各种格式 7 8 // Decode video frame 9 avcodec_decode_video2(pstream_info->dec_ctx, pDecodeFrame, &frameFinished,&pkt); 10 if(frameFinished) 11 { 12 if (pstream_info->dec_ctx->pix_fmt == AV_PIX_FMT_YUV420P) //如果是yuv420p的 13 { 14 for(i = 0; i < pstream_info->dec_ctx->height; i++) 15 { 16 memcpy(video_decode_buf+pstream_info->dec_ctx->width*i, 17 pDecodeFrame->data[0]+pDecodeFrame->linesize[0]*i, 18 pstream_info->dec_ctx->width); 19 } 20 for(j = 0; j < pstream_info->dec_ctx->height/2; j++) 21 { 22 memcpy(video_decode_buf+pstream_info->dec_ctx->width*i+pstream_info->dec_ctx->width/2*j, 23 pDecodeFrame->data[1]+pDecodeFrame->linesize[1]*j, 24 pstream_info->dec_ctx->width/2); 25 } 26 for(k =0; k < pstream_info->dec_ctx->height/2; k++) 27 { 28 memcpy(video_decode_buf+pstream_info->dec_ctx->width*i+pstream_info->dec_ctx->width/2*j+pstream_info->dec_ctx->width/2*k, 29 pDecodeFrame->data[2]+pDecodeFrame->linesize[2]*k, 30 pstream_info->dec_ctx->width/2); 31 } 32 } 33 else if (pstream_info->dec_ctx->pix_fmt == AV_PIX_FMT_YUV422P)//如果是yuv422p的 34 { 35 for(i = 0; i < pstream_info->dec_ctx->height; i++) 36 { 37 memcpy(video_decode_buf+pstream_info->dec_ctx->width*i, 38 pDecodeFrame->data[0]+pDecodeFrame->linesize[0]*i, 39 pstream_info->dec_ctx->width); 40 } 41 for(j = 0; j < pstream_info->dec_ctx->height; j++) 42 { 43 memcpy(video_decode_buf+pstream_info->dec_ctx->width*i+pstream_info->dec_ctx->width/2*j, 44 pDecodeFrame->data[1]+pDecodeFrame->linesize[1]*j, 45 pstream_info->dec_ctx->width/2); 46 } 47 for(k =0; k < pstream_info->dec_ctx->height; k++) 48 { 49 memcpy(video_decode_buf+pstream_info->dec_ctx->width*i+pstream_info->dec_ctx->width/2*j+pstream_info->dec_ctx->width/2*k, 50 pDecodeFrame->data[2]+pDecodeFrame->linesize[2]*k, 51 pstream_info->dec_ctx->width/2); 52 } 53 } 54 else 55 { 56 //可扩展 57 } 58 video_decode_size = avpicture_get_size(pstream_info->dec_ctx->pix_fmt, pstream_info->dec_ctx->width,pstream_info->dec_ctx->height); 59 new_videosize = video_decode_size; 60 61 //缩放或格式转换 62 if (pstream_info->dec_ctx->width != Zoom_Width || 63 pstream_info->dec_ctx->height != Zoom_Height || 64 pstream_info->dec_ctx->pix_fmt != Zoom_pix_fmt) 65 { 66 new_videosize = VideoScaleYuvZoom(Is_flip,pstream_info->dec_ctx->width ,pstream_info->dec_ctx->height,(int)pstream_info->dec_ctx->pix_fmt, 67 Zoom_Width,Zoom_Height,Zoom_pix_fmt,video_decode_buf); 68 } 69 //这里可以取出数据 70 frame_info->stream_idx = pstream_info->stream_idx; 71 //frame_info->pts = pDecodeFrame->pkt_pts * 1000 * av_q2d(pstream_info->stream->time_base); //转化成毫秒 72 frame_info->pts = pDecodeFrame->pkt_pts; 73 frame_info->timebase_den = pstream_info->stream->time_base.den; 74 frame_info->timebase_num = pstream_info->stream->time_base.num; 75 frame_info->bufsize = new_videosize; 76 memcpy(frame_info->buf,video_decode_buf,new_videosize); 77 } 78 else 79 { 80 //缓存 81 frame_info->stream_idx = pstream_info->stream_idx; 82 frame_info->pts = 0; 83 frame_info->timebase_den = 0; 84 frame_info->timebase_num = 0; 85 frame_info->bufsize = 0; 86 memset(frame_info->buf,0,MAX_FRAME_SIZE); 87 } 88 if (video_decode_buf) 89 { 90 free(video_decode_buf); 91 video_decode_buf = NULL; 92 } 93 video_decode_size = 0; 94 }
也可以把YUV数据进行存储为PPM格式(Linux系统下的图片格式):
1 //如果是视频 2 else if (pstream_info[i].dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) 3 { 4 // Decode video frame 5 avcodec_decode_video2(pstream_info->dec_ctx, pDecodeFrame, &frameFinished,&pkt); 6 if(frameFinished) 7 { 8 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); 9 if((++k<=30) && (k%3==0)) { 10 SaveFrame(pFrameYUV, pCodecCtx->width, pCodecCtx->height, k); 11 } 12 } 13 } 14 15 void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) 16 { 17 FILE *pFile; 18 char szFilename[32]; 19 int y; 20 21 SDL_Log("%d * %d", width, height); 22 // Open file 23 sprintf(szFilename, "frame/frame%d.ppm", iFrame); 24 pFile=fopen(szFilename, "wb"); 25 if(pFile==NULL) 26 return; 27 28 // Write header 29 fprintf(pFile, "P6 %d %d 255 ", width, height); 30 31 // Write pixel data 32 for(y=0; y<height; y++) { 33 fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile); 34 } 35 36 // Close file 37 fclose(pFile); 38 }