录制h264播放时遇到花屏问题

来源:11-9 实战NV12转YUV420P

邓丹俊

2025-02-10

老师好,我的摄像头数据是yuyv422的,用sws_scale转换为yuv420p后进行h264编码后发现yuv视频正常播放,但是h264播放花屏,且有报错,应该修改哪里的代码呢
代码如下:
extern “C”
{
#define __STDC_CONSTANT_MACROS 1
#include “libavutil/avutil.h”
#include “libavdevice/avdevice.h”
#include “libavformat/avformat.h”
#include “libavcodec/avcodec.h”
#include “libswresample/swresample.h”
#include “libavutil/audio_fifo.h”
#include “libavutil/imgutils.h”
#include “libswscale/swscale.h”
}
#include
#include
#include
#include

using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::copy;
using std::ofstream;
using std::cout;

int main()
{
int ret{}, count{};
char err[1024];
ofstream file422,file264;
file422 = ofstream(“d:/video.yuv”, std::ios::trunc);
if (!file422)
return -1;
file422 << “”;
file422.close();
file264 = ofstream(“d:/video.h264”, std::ios::trunc);
if (!file264)
return -1;
file264 << “”;
file264.close();
file422 = ofstream(“d:/video.yuv”, std::ios::app);
if (!file422)
return -1;
file264 = ofstream(“d:/video.h264”, std::ios::app);
if (!file264)
return -1;

avdevice_register_all();

auto fmt = av_find_input_format("dshow");
if (!fmt)
{
	cout << "av_find_input_format fail\n";
	return -1;
}

AVFormatContext *ps{};
const char *url{ u8"video=Surface Camera Front" };

AVDictionary *options{};

ret = av_dict_set(&options, "video_size", "640x480",0);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "av_dict_set video_size:" << ret << ":" << err << "\n";
	return -1;
}
ret = av_dict_set(&options, "framerate", "30", 0);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "av_dict_set framerate:" << ret << ":" << err << "\n";
	return -1;
}
ret = av_dict_set(&options, "pix_fmt", "yuyv422", 0);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "av_dict_set pix_fmt:" << ret << ":" << err << "\n";
	return -1;
}

ret = avformat_open_input(&ps,url,fmt,&options);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "avformat_open_input:" << ret << ":" << err << "\n";
	return -1;
}

ret = avformat_find_stream_info(ps, nullptr);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "avformat_find_stream_info:" << ret << ":" << err << "\n";
	return -1;
}

av_dump_format(ps, 0, url, 0);

///////////////////////////////////////////////////////////////


auto codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
	cout << "avcodec_find_encoder fail\n";
	return -1;
}


auto ctx = avcodec_alloc_context3(codec);
if (!ctx)
{
	cout << "avcodec_alloc_context3 fail\n";
	return -1;
}

ctx->width = 640;
ctx->height = 480;
ctx->gop_size = 250;

ctx->pix_fmt = AV_PIX_FMT_YUV420P;
ctx->profile = AV_PROFILE_H264_HIGH_444;
ctx->level = 50;

ctx->framerate = AVRational{ 25,1 };
ctx->time_base= AVRational{ 1,25 };

ret = av_opt_set(ctx->priv_data, "preset", "slow", 0);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "av_opt_set:" << ret << ":" << err << "\n";
	return -1;
}

ret = avcodec_open2(ctx, codec, nullptr);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "avcodec_open2:" << ret << ":" << err << "\n";
	return -1;
}

AVFrame *frame420,*frame422;
frame420 = av_frame_alloc();
if (!frame420)
{
	cout << "av_frame_alloc frame420 fail\n";
	return -1;
}
frame422 = av_frame_alloc();
if (!frame422)
{
	cout << "av_frame_alloc frame422 fail\n";
	return -1;
}


frame420->width = 640;
frame420->height = 480;
frame420->format = AV_PIX_FMT_YUV420P;
ret = av_frame_get_buffer(frame420, 32);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "av_frame_get_buffer frame420:" << ret << ":" << err << "\n";
	return -1;
}

frame422->width = 640;
frame422->height = 480;
frame422->format = AV_PIX_FMT_YUYV422;

ret = av_frame_get_buffer(frame422, 32);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "av_frame_get_buffer frame422:" << ret << ":" << err << "\n";
	return -1;
}


enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUYV422;
enum AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P;
int width = 640;  // 图像宽度
int height = 480; // 图像高度

// 创建视频帧转换上下文 从YUYV422转换到YUV420P
SwsContext *sws_ctx = sws_getContext(width, height, src_pix_fmt,
	width, height, dst_pix_fmt,
	SWS_BICUBIC, NULL, NULL, NULL);
if (!sws_ctx) {
	cout<<"Could not initialize the conversion context\n";
	return -1;
}

///////////////////////////////////////////////

AVPacket pkt[200],*newpkt;
newpkt = av_packet_alloc();
if (!newpkt)
{
	cout << "av_packet_alloc fail\n";
	return -1;
}

for (int i = 0; i != 200; ++i)
{
	ret = av_read_frame(ps, &pkt[i]);
	if (ret < 0)
	{
		av_strerror(ret, err, 1024);
		cout << "av_read_frame:" << ret << ":" << err << "\n";
		return -1;
	}
}

avformat_close_input(&ps);



//307200   460800  76800   384000   460800  614400

for (int i = 0; i != 200; ++i)
{
	//拷贝数据到yuyv422中  width*height*2  640*480*2
	copy(pkt[i].data, pkt[i].data + 614400, frame422->data[0]);

	//视频帧转换
	ret = sws_scale(sws_ctx, frame422->data, frame422->linesize, 0, height,
		frame420->data, frame420->linesize);
	if (ret < 0)
	{
		av_strerror(ret, err, 1024);
		cout << "sws_scale:" << ret << ":" << err << "\n";
		return -1;
	}

	frame420->pts = i;

	ret = avcodec_send_frame(ctx, frame420);

	while (ret >= 0)
	{
		ret = avcodec_receive_packet(ctx, newpkt);
		if (ret < 0)
			break;

		file264.write(reinterpret_cast<char*>(newpkt->data), newpkt->size);
	}

	file422.write(reinterpret_cast<char*>(pkt[i].data), 614400);

	av_packet_unref(&pkt[i]);
}

ret = avcodec_send_frame(ctx, nullptr);

while (ret >= 0)
{
	ret = avcodec_receive_packet(ctx, newpkt);
	if (ret < 0)
		break;

	file264.write(reinterpret_cast<char*>(newpkt->data), newpkt->size);
}



sws_freeContext(sws_ctx);
av_packet_free(&newpkt);
av_frame_free(&frame422);
av_frame_free(&frame420);
file264.close();
file422.close();

av_log_set_level(AV_LOG_DEBUG);
av_log(nullptr, AV_LOG_INFO, "finish\n");

return 0;

}
yuv播放如下:
图片描述
h264播放如下:
图片描述
图片描述
图片描述
图片描述

写回答

1回答

李超

2025-02-10

你将YUV422转成YUV420后有播放过吗,我估计你这步出错了

0
2
邓丹俊
老师你好,我测试了,新代码另开一个问题提问
2025-02-10
共2条回复

音视频小白系统入门课 音视频基础+ffmpeg原理

掌握音视频采集、编解码、RTMP传输协议等核心基础

2317 学习 · 813 问题

查看课程