先貼代碼, 有空再補充。ide
H264 是幀間編碼,須要連續多幀喂數據給AVCodecContext才能正確解碼。編碼
void H264ToRGB(unsigned char* data, unsigned int dataSize, unsigned char* outBuffer) { // 1. 將元數據裝填到packet AVPacket* avPkt = av_packet_alloc(); avPkt->size = dataSize; avPkt->data = data; static AVCodecContext* codecCtx = nullptr; if (codecCtx == nullptr) { // 2. 建立並配置codecContext AVCodec* h264Codec = avcodec_find_decoder(AV_CODEC_ID_H264); codecCtx = avcodec_alloc_context3(h264Codec); avcodec_get_context_defaults3(codecCtx, h264Codec); avcodec_open2(codecCtx, h264Codec, nullptr); } // 3. 解碼 //avcodec_decode_video2(codecCtx, &outFrame, &lineLength, &avPkt); // 接口被棄用,使用下邊接口代替 auto ret = avcodec_send_packet(codecCtx, avPkt); if (ret >= 0) { AVFrame* YUVFrame = av_frame_alloc(); ret = avcodec_receive_frame(codecCtx, YUVFrame); if (ret >= 0) { // 4.YUV轉RGB24 AVFrame* RGB24Frame = av_frame_alloc(); struct SwsContext* convertCxt = sws_getContext( YUVFrame->width, YUVFrame->height, AV_PIX_FMT_YUV420P, YUVFrame->width, YUVFrame->height, AV_PIX_FMT_RGB24, SWS_POINT, NULL, NULL, NULL ); // outBuffer將會分配給RGB24Frame->data,AV_PIX_FMT_RGB24格式只分配到RGB24Frame->data[0] av_image_fill_arrays( RGB24Frame->data, RGB24Frame->linesize, outBuffer, AV_PIX_FMT_RGB24, YUVFrame->width, YUVFrame->height, 1 ); sws_scale(convertCxt, YUVFrame->data, YUVFrame->linesize, 0, YUVFrame->height, RGB24Frame->data, RGB24Frame->linesize); // 5.清除各對象/context -> 釋放內存 // free context and avFrame sws_freeContext(convertCxt); av_frame_free(&RGB24Frame); // RGB24Frame. } // free context and avFrame av_frame_free(&YUVFrame); } // free context and avFrame av_packet_unref(avPkt); av_packet_free(&avPkt); // avcodec_free_context(&codecCtx); }
MJPEG 是幀內編碼,每幀MJPEG幀均可以解碼出對應RGB幀。code
void MJPEGToRGB(unsigned char *data, unsigned int dataSize, unsigned char *outBuffer) { // 1. 將元數據裝填到packet AVPacket *avPkt = av_packet_alloc(); avPkt->size = dataSize; avPkt->data = data; // 2. 建立並配置codecContext AVCodec *mjpegCodec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); AVCodecContext* codecCtx = avcodec_alloc_context3(mjpegCodec); avcodec_get_context_defaults3(codecCtx, mjpegCodec); avcodec_open2(codecCtx, mjpegCodec, nullptr); // 3. 解碼 //avcodec_decode_video2(codecCtx, &outFrame, &lineLength, &avPkt); // 接口被棄用,使用下邊接口代替 auto ret = avcodec_send_packet(codecCtx, avPkt); if (ret >=0) { AVFrame* YUVFrame = av_frame_alloc(); ret = avcodec_receive_frame(codecCtx, YUVFrame); if (ret >= 0) { // 4.YUV轉RGB24 AVFrame* RGB24Frame = av_frame_alloc(); struct SwsContext* convertCxt = sws_getContext( YUVFrame->width, YUVFrame->height, AV_PIX_FMT_YUV420P, YUVFrame->width, YUVFrame->height, AV_PIX_FMT_RGB24, SWS_POINT, NULL, NULL, NULL ); // outBuffer將會分配給RGB24Frame->data,AV_PIX_FMT_RGB24格式只分配到RGB24Frame->data[0] av_image_fill_arrays( RGB24Frame->data, RGB24Frame->linesize, outBuffer, AV_PIX_FMT_RGB24, YUVFrame->width, YUVFrame->height, 1 ); sws_scale(convertCxt, YUVFrame->data, YUVFrame->linesize, 0, YUVFrame->height, RGB24Frame->data, RGB24Frame->linesize); // 5.清除各對象/context -> 釋放內存 // free context and avFrame sws_freeContext(convertCxt); av_frame_free(&RGB24Frame); // RGB24Frame. } // free context and avFrame av_frame_free(&YUVFrame); } // free context and avFrame av_packet_unref(avPkt); av_packet_free(&avPkt); avcodec_free_context(&codecCtx); }