C语言实现RGB packet格式转YUV(NV21)格式

前言:

此函数用于RGB packet(R G B R G B······)格式转YUV的NV21格式,保存NV21图像的内存由外部申请并传入。函数的具体实现原理在这里不做介绍,对RGB格式和YUV格式不熟悉的请自行查阅资料,该函数可直接拷贝过去使用。

代码:

/*
* 输入:data--RGB的数据
* 	w--RGB图像的宽
* 	h--RGB图像的高
* 输出:yuv--转换得到的yuv数据
*/
void RgbToNv12(Uint8* data, Uint32 w, Uint32 h, Uint8* yuv)
{
    Uint32 row_bytes;
    Uint8* uv;
    Uint8* y;
    Uint8 r, g, b;
    Uint8 y_val, u_val, v_val;
   
    Uint8 * img;
    Uint32 i, j;
    y = yuv;
    uv = yuv + w * h;

    row_bytes = (w * 3 );  
    h = h & ~1;
    //先转换Y
    for (i = 0; i < h; i++)
    {   
        img = data + row_bytes * i;
        for (j = 0; j <w; j++)
        {
            r = *(img+3*j);
            g = *(img+3*j+1);
            b = *(img+3*j+2);
            if(r>=254&&g>=254&&b>=254)
            {
    	        y_val=254;
    	        *y++ = y_val;
   	        continue;
            }
           y_val = (Uint8)(((int32)(299 * r) + (int32)(597 * g) + (int32)(114 * b)) / 1000);
           *y++ = y_val;
        }
    }
    //转换uv  
    for (i = 0; i <h; i += 2)
    {
	img = data + row_bytes * i;
 	for (j = 0; j < w; j+=2)
  	{
	    r = *(img+3*j);
	    g = *(img+3*j+1);
	    b = *(img+3*j+2);
	    u_val= (Uint8)(((int32)(-168.7 * r) - (int32)(331.3 * g) + (int32)(500 * b) + 128000) / 1000);
	    v_val= (Uint8)(((int32)(500 * r) - (int32)(418.7 * g) - (int32)(81.3 * b) + 128000) / 1000);
	    *uv++ = v_val;
	    *uv++ = u_val;
	}
   }
}	         
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实现 H264 帧 YUV 帧的过程,可以分为如下几个步骤: 1. 读取 H264 数据,将其解码成原始的 YUV 数据。 2. 将 YUV 数据存储到文件中。 下面是一个示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #define INBUF_SIZE 4096 int main(int argc, char *argv[]) { AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVPacket packet; AVFrame *pFrame = NULL; AVFrame *pFrameYUV = NULL; uint8_t *buffer = NULL; int videoStream = -1; int frameFinished = 0; int numBytes = 0; struct SwsContext *img_convert_ctx = NULL; if (argc < 3) { printf("Usage: %s <input_file> <output_file>\n", argv[0]); return -1; } av_register_all(); if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) { printf("Error: Couldn't open input file.\n"); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Error: Couldn't find stream information.\n"); return -1; } for (int i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; break; } } if (videoStream == -1) { printf("Error: Couldn't find video stream.\n"); return -1; } pCodecCtx = avcodec_alloc_context3(NULL); if (!pCodecCtx) { printf("Error: Couldn't allocate codec context.\n"); return -1; } avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar); pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { printf("Error: Couldn't find codec.\n"); return -1; } if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("Error: Couldn't open codec.\n"); return -1; } pFrame = av_frame_alloc(); pFrameYUV = av_frame_alloc(); if (!pFrame || !pFrameYUV) { printf("Error: Couldn't allocate frames.\n"); return -1; } numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); if (!buffer) { printf("Error: Couldn't allocate buffer.\n"); return -1; } av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, 0, NULL, NULL, NULL); if (!img_convert_ctx) { printf("Error: Couldn't initialize conversion context.\n"); return -1; } FILE *fp_out = fopen(argv[2], "wb"); if (!fp_out) { printf("Error: Couldn't open output file.\n"); return -1; } while (av_read_frame(pFormatCtx, &packet) >= 0) { if (packet.stream_index == videoStream) { avcodec_send_packet(pCodecCtx, &packet); while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) { sws_scale(img_convert_ctx, (const uint8_t *const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); fwrite(pFrameYUV->data[0], 1, pCodecCtx->width * pCodecCtx->height, fp_out); fwrite(pFrameYUV->data[1], 1, pCodecCtx->width * pCodecCtx->height / 4, fp_out); fwrite(pFrameYUV->data[2], 1, pCodecCtx->width * pCodecCtx->height / 4, fp_out); } av_packet_unref(&packet); } } fclose(fp_out); av_free(buffer); av_frame_free(&pFrameYUV); av_frame_free(&pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; } ``` 其中,`AVFormatContext` 用于存储输入文件的格式信息,`AVCodecContext` 用于存储编解码器的上下文信息,`AVCodec` 用于存储编解码器的信息,`AVPacket` 用于存储解码后的数据帧,`AVFrame` 用于存储解码后的数据帧,`SwsContext` 用于存储图像换上下文信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值