当前位置:网站首页>Video player (II): video decoding
Video player (II): video decoding
2022-06-30 07:19:00 【Wood fire zero】
List of articles
1. FFmpeg Decoding process
2. Code
std::string input_file = "1.mp4";
std::string output_file = "1.yuv";
// Create output file
FILE *out_fd = nullptr;
out_fd = fopen(output_file.c_str(), "wb");
if (!out_fd)
{
printf("can't open output file");
return;
}
AVFormatContext *fmt_ctx = nullptr;
fmt_ctx = avformat_alloc_context();
// Open the input video file
int ret = avformat_open_input(&fmt_ctx, input_file.c_str(), nullptr, nullptr);
if(ret < 0)
{
av_log(nullptr, AV_LOG_ERROR, "can not open input: %s \n", err2str(ret).c_str());
return;
}
// Get video file information
ret = avformat_find_stream_info(fmt_ctx, nullptr);
if(ret < 0)
{
av_log(nullptr, AV_LOG_ERROR, "avformat_find_stream_info failed: %s \n", err2str(ret).c_str());
return;
}
// Print video information
//av_dump_format(fmt_ctx, 0, input_file.c_str(), 0); // Fourth parameter , The input stream is 0, The output stream is 1
// Find video stream sequence number
int video_index = -1;
for (int i = 0; i < fmt_ctx->nb_streams; ++i)
{
if(fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_index = i;
}
}
if(video_index == -1)
{
av_log(nullptr, AV_LOG_ERROR, "can not find video \n");
return;
}
// Find the video stream decoder
const AVCodec *video_codec = avcodec_find_decoder(fmt_ctx->streams[video_index]->codecpar->codec_id);
AVCodecContext *codec_ctx = avcodec_alloc_context3(video_codec);
avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_index]->codecpar);
// Turn on the video decoder
ret = avcodec_open2(codec_ctx, video_codec, nullptr);
if(ret < 0)
{
av_log(nullptr, AV_LOG_ERROR, "avcodec_open2 failed: %s \n", err2str(ret).c_str());
return;
}
// other YUV Format to YUV420P
SwsContext *img_convert_ctx = nullptr;
img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
// establish packet, Used to store data before decoding
AVPacket packet;
av_init_packet(&packet);
// establish Frame, Used to store decoded data
AVFrame *frame = av_frame_alloc();
frame->width = fmt_ctx->streams[video_index]->codecpar->width;
frame->height = fmt_ctx->streams[video_index]->codecpar->height;
frame->format = fmt_ctx->streams[video_index]->codecpar->format;
av_frame_get_buffer(frame, 32);
// establish YUV Frame, Used to store decoded data
AVFrame *yuv_frame = av_frame_alloc();
yuv_frame->width = fmt_ctx->streams[video_index]->codecpar->width;
yuv_frame->height = fmt_ctx->streams[video_index]->codecpar->height;
yuv_frame->format = AV_PIX_FMT_YUV420P;
av_frame_get_buffer(yuv_frame, 32);
// while loop , Read one frame at a time , Parallel transcoding
while (av_read_frame(fmt_ctx, &packet) >= 0)
{
if(packet.stream_index == video_index)
{
// Start decoding
// Send data to the decoding queue
// used API:avcodec_decode_video2
// new API:avcodec_send_packet And avcodec_receive_frame
ret = avcodec_send_packet(codec_ctx, &packet);
if (ret < 0)
{
av_log(nullptr, AV_LOG_ERROR, "avcodec_send_packet failed: %s \n", err2str(ret).c_str());
break;
}
while (avcodec_receive_frame(codec_ctx, frame) >= 0)
{
//
sws_scale(img_convert_ctx,
(const uint8_t **)frame->data,
frame->linesize,
0,
codec_ctx->height,
yuv_frame->data,
yuv_frame->linesize);
// Data written to yuv In file
int y_size = codec_ctx->width * codec_ctx->height;
fwrite(yuv_frame->data[0], 1, y_size, out_fd);
fwrite(yuv_frame->data[1], 1, y_size/4, out_fd);
fwrite(yuv_frame->data[2], 1, y_size/4, out_fd);
}
}
av_packet_unref(&packet);
}
if (out_fd)
{
fclose(out_fd);
}
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
among :
std::string err2str(int err)
{
char errStr[1024] = {
0};
av_strerror(err, errStr, sizeof(errStr));
return errStr;
}
After transcoding , Use pplay Play :
convert to yuv after , Play : ffplay -s 640x352 -pix_fmt yuv420p 1.yuv
-s 640x352 For video wide x high
3. explain
3.1 sws_getContext
struct SwsContext* sws_getContext(int srcW,
int srcH,
enum AVPixelFormat srcFormat,
int dstW,
int dstH,
enum AVPixelFormat dstFormat,
int flags,
SwsFilter *srcFilter,
SwsFilter *dstFilter,
const double *param )
Parameters :
- srcW Of the source video frame width;
- srcH Of the source video frame height;
- srcFormat The pixel format of the source video frame format;
- dstW Of converted video frames width;
- dstH Of converted video frames height;
- dstFormat The pixel format of the converted video frame format;
- flags Algorithm of transformation
- srcFilter、dstFilter Define the inputs separately / Output image filter information , If you do not filter the front and back images , Input NULL;
- param Define the parameters required for a particular scaling algorithm , The default is NULL
The function returns SwsContext Structure , Basic transformation information is defined
Example :
sws_getContext(w, h, YV12, w, h, NV12, 0, NULL, NULL, NULL); // YV12->NV12 Color space conversion
sws_getContext(w, h, YV12, w/2, h/2, YV12, 0, NULL, NULL, NULL); // YV12 Reduce the image to the original image 1/4
sws_getContext(w, h, YV12, 2w, 2h, YN12, 0, NULL, NULL, NULL); // YV12 Enlarge the image to the original 4 times , And converted to NV12 structure
3.2 sws_scale
int sws_scale(struct SwsContext *c,
const uint8_t *const srcSlice[],
const int srcStride[],
int srcSliceY,
int srcSliceH,
uint8_t *const dst[],
const int dstStride[] )
Parameters :
- c By sws_getContext Obtained parameters ;
- srcSlice[] input data buffer;
- srcStride[] For each column byte Count , Than actual width It's worth more ;
- srcSliceY The first column deals with the location ; Here I deal with it from the beginning , So fill it directly 0;
- srcSliceH Height ;
- dst[] Target data buffer;
- dstStride[] Same as srcStride[]
After decoding YUV The video pixel data in format is saved in AVFrame Of data[0]、data[1]、data[2] in , But these pixel values are not stored continuously , Some invalid pixels are stored after each row of valid pixels .
With brightness Y Take the data ,data[0] It includes linesize[0]*height Data . But in the consideration of optimization, etc ,linesize[0] Actually, it's not equal to the width width, It's a value larger than the width . Therefore, it is necessary to use sws_scale() convert , Invalid data is removed after conversion ,width And linesize[0] The values are equal .
4. Reference material
https://ffmpeg.org/doxygen/trunk/group__libsws.html#gae531c9754c9205d90ad6800015046d74
https://www.cnblogs.com/cyyljw/p/8676062.html
ffmpeg Code implementation h264 turn yuv
《 be based on FFmpeg + SDL The production of video player 》 Video of the course
边栏推荐
- 1285_ Expand macros defined by AUTOSAR functions and variables with scripts to improve readability
- Grep command usage
- The maximum expression in Oracle database message list is 1000 error
- 网络安全-ARP协议和防御
- 单测调用对象的私有方法
- Starting MySQL ERROR! Couldn‘t find MySQL server (/usr/local/mysql/bin/mysqld_safe)
- Linu基础-分区规划与使用
- Linu foundation - zoning planning and use
- 手机开户股票开户安全吗?开户需要准备什么?
- Ad usage notes
猜你喜欢
随机推荐
Cubemx completes STM32F103 dual serial port 485 transceiver transmission
如果我在珠海,到哪里开户比较好?另外,手机开户安全么?
Mysql5.7 compressed version installation tutorial
All errors reported by NPM
03 - programming framework: Division of application layer, middle layer and driver layer in bare metal programming
Grep command usage
Embedded test process
Linux服务器安装Redis
Running lantern effect JS text rotation effect realization
QT common macro definitions
Network security ARP protocol and defense
Keil serial port redirection
Resolution: div failed to get keyboard event
The maximum expression in Oracle database message list is 1000 error
Egret engine P2 physics engine (2) - Funny physical phenomenon of small balls hitting the ground
QT signal slot alarm QObject:: connect:cannot connect (null)
Utilisation de la commande grep
B站首个UP主付费观看视频还是来了!价格“劝退”网友
将本地电脑文件复制到虚拟机系统中详细方法
Network security - packet capture and IP packet header analysis