yuv文件测试

我们要测试的文件foreman_part_qcif.yuv它包含三帧彩色图像。

以及文件foreman_part_qcif.y 注意后缀,它包含三帧灰度图像(只有y信号)

qicf文件的分辨率为176*144,并且每个分量用一个字节存储

则对于foreman_part_qcif.yuv文件,用于表达颜色的字节大小应该为:

3[帧数]*{176*144[亮度]+(1/4)*176*144[u色度信号]+(1/4)*176*144[v色度信号]}= 114048

查看该文件的大小后发现确为114,048 字节

说明该文件不同于其他图像格式的文件(bmp,jpeg等),它没有文件头,没有任何与表达颜色信号无关的内容。

用十六进制编辑器打开两个文件进行比对,如下图:

它们开始的内容是一样的。

从下面的两幅图可以看出:

两个文件从6300h(十六进制)之后开始出现不同,6300h转化为十进制是176*144=25344

刚好是y信号所占用的字节的大小。

对于文件foreman_part_qcif.yuv 它从6301h起开始排列第一帧的u信号。

对于文件foreman_part_qcif.y 它从6301h起开始排列第二帧的y信号。

由以上分析可以得出4:2:0的qcif.yuv文件的格式如下图:

cif文件的分辨率为352*288,

qcif即1/4的cif为176*144,

4:2:0的qcif.yuv文件结构

yuv文件不能直接在windows底下打开,通过工具YUVview可以显示该文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将 YUV 数据编码为视频文件,可以使用 ffmpeg 库提供的 API。以下是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavutil/imgutils.h> #include <libavutil/opt.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> int main(int argc, char *argv[]) { int ret = 0; AVFormatContext *format_ctx = NULL; AVOutputFormat *output_fmt = NULL; AVStream *video_stream = NULL; AVCodec *codec = NULL; AVCodecContext *codec_ctx = NULL; AVPacket pkt = { 0 }; int video_frame_count = 0; int video_width = 640; int video_height = 480; int video_fps = 25; const char *output_filename = "output.mp4"; // 初始化 FFmpeg 库 av_register_all(); // 打开输出文件 ret = avformat_alloc_output_context2(&format_ctx, NULL, NULL, output_filename); if (ret < 0) { fprintf(stderr, "Failed to allocate output format context: %s\n", av_err2str(ret)); return ret; } output_fmt = format_ctx->oformat; // 添加视频流 codec = avcodec_find_encoder(output_fmt->video_codec); if (!codec) { fprintf(stderr, "Failed to find video encoder\n"); ret = AVERROR(EINVAL); goto end; } video_stream = avformat_new_stream(format_ctx, codec); if (!video_stream) { fprintf(stderr, "Failed to create video stream\n"); ret = AVERROR(EINVAL); goto end; } codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { fprintf(stderr, "Failed to allocate codec context\n"); ret = AVERROR(ENOMEM); goto end; } codec_ctx->width = video_width; codec_ctx->height = video_height; codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; codec_ctx->time_base = (AVRational) { 1, video_fps }; codec_ctx->framerate = (AVRational) { video_fps, 1 }; codec_ctx->gop_size = 10; codec_ctx->max_b_frames = 1; codec_ctx->bit_rate = 400000; codec_ctx->rc_min_rate = codec_ctx->rc_max_rate = codec_ctx->bit_rate; codec_ctx->sample_aspect_ratio = (AVRational) { 1, 1 }; if (format_ctx->oformat->flags & AVFMT_GLOBALHEADER) codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; ret = avcodec_open2(codec_ctx, codec, NULL); if (ret < 0) { fprintf(stderr, "Failed to open video encoder: %s\n", av_err2str(ret)); goto end; } ret = avcodec_parameters_from_context(video_stream->codecpar, codec_ctx); if (ret < 0) { fprintf(stderr, "Failed to copy codec parameters: %s\n", av_err2str(ret)); goto end; } av_dump_format(format_ctx, 0, output_filename, 1); // 打开输出文件并写文件头 ret = avio_open(&format_ctx->pb, output_filename, AVIO_FLAG_WRITE); if (ret < 0) { fprintf(stderr, "Failed to open output file: %s\n", av_err2str(ret)); goto end; } ret = avformat_write_header(format_ctx, NULL); if (ret < 0) { fprintf(stderr, "Failed to write file header: %s\n", av_err2str(ret)); goto end; } // 编码 YUV 数据并写入文件 int y_size = video_width * video_height; int uv_size = y_size / 4; uint8_t *y_data = (uint8_t *) malloc(y_size); uint8_t *u_data = (uint8_t *) malloc(uv_size); uint8_t *v_data = (uint8_t *) malloc(uv_size); for (int i = 0; i < 300; i++) { // 生成测试数据 for (int j = 0; j < y_size; j++) { y_data[j] = i % 255; } for (int j = 0; j < uv_size; j++) { u_data[j] = (i + j) % 255; v_data[j] = (i + j + uv_size) % 255; } // 将 YUV 数据填充到 AVFrame 中 AVFrame *frame = av_frame_alloc(); frame->width = video_width; frame->height = video_height; frame->format = AV_PIX_FMT_YUV420P; av_image_fill_arrays(frame->data, frame->linesize, y_data, video_width, u_data, video_width / 2, v_data, video_width / 2, AV_PIX_FMT_YUV420P, 1); // 编码 AVFrame 并写入文件 ret = avcodec_send_frame(codec_ctx, frame); if (ret < 0) { fprintf(stderr, "Error sending frame: %s\n", av_err2str(ret)); av_frame_free(&frame); goto end; } while (ret >= 0) { ret = avcodec_receive_packet(codec_ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { fprintf(stderr, "Error receiving packet: %s\n", av_err2str(ret)); goto end; } pkt.stream_index = video_stream->index; av_packet_rescale_ts(&pkt, codec_ctx->time_base, video_stream->time_base); pkt.pts = video_frame_count * video_stream->time_base.den / (video_stream->time_base.num * video_fps); pkt.dts = pkt.pts; pkt.duration = video_stream->time_base.den / (video_stream->time_base.num * video_fps); pkt.pos = -1; av_interleaved_write_frame(format_ctx, &pkt); av_packet_unref(&pkt); } av_frame_free(&frame); video_frame_count++; } // 写文件尾并释放资源 av_write_trailer(format_ctx); end: if (codec_ctx) { avcodec_free_context(&codec_ctx); } if (format_ctx) { if (format_ctx->pb) { avio_closep(&format_ctx->pb); } avformat_free_context(format_ctx); } if (ret < 0) { fprintf(stderr, "Error occurred: %s\n", av_err2str(ret)); return 1; } return 0; } ``` 在这个示例代码中,我们首先使用 avformat_alloc_output_context2 函数创建一个 AVFormatContext 对象,然后使用 avformat_new_stream 函数为该对象添加一个视频流。接着,我们使用 AVCodecContext 结构体设置了视频流的一些参数,例如分辨率、帧率、编码格式等。然后,我们使用 avcodec_open2 函数打开了该编码器,并使用 avcodec_parameters_from_context 函数将编码器参数复制到视频流的 codecpar 结构体中。最后,我们打开输出文件并写入文件头,然后循环编码 YUV 数据并将编码后的数据写入文件中,最后写入文件尾并释放资源。 需要注意的是,在编码每一帧数据时,我们需要将 AVFrame 转换成编码器所需的格式,并使用 avcodec_send_frame 函数发送该 AVFrame,然后使用 avcodec_receive_packet 函数接收编码器编码后的数据。在将编码后的数据写入文件前,需要将编码后的时间戳 PTS 和 DTS 进行适当的转换和设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值