当前位置:网站首页>Player actual combat 16 xdecode class
Player actual combat 16 xdecode class
2022-06-12 14:09:00 【Sister Suo】
1.xdecode.h
class xdecode
{
public:
bool isAudio=false;
//pa After the parameters pointing to the space are passed to the decoder, the data in this space is useless , Need to free up this space , Failure to free will result in memory leaks ,
// Release before all returns of this function ( Both success and error need to be released )
virtual bool open(AVCodecParameters* pa);
virtual void close();
virtual void clear();
// take packet Send to decoding buffer queue , And empty pkt Space ( Objects and media content )
virtual bool send(AVPacket*pkt);
// Receive the decoded frame in the decoding buffer queue , once send Corresponding multiple times receive,send When it's over, I have to receive Make sure you empty
virtual AVFrame* receive(int&r);
protected:
AVCodecContext* codeccontext = 0;
std::mutex mux;
};
and demux Similar to class , take mux The lock and context variables are set to protected
2.main How to use... In functions
xdecode vdecode;
cout << "vdecode.open()" << vdecode.open(demux.CopyVPara()) << endl;
xdecode adecode;
cout << "adecode.open()" << adecode.open(demux.CopyAPara()) << endl;
int i = 0;
for (;;)
{
AVPacket* pkt = demux.readfz();// After reading one packet Automatically read the next
if (vdecode.isAudio == false)
{
cout<<"send"<<vdecode.send(pkt)<<endl;
for (;;)
{
int re = 0;
AVFrame* frame = vdecode.receive(re);
if (re != 0)break;
}
}
if (adecode.isAudio == true)
{
cout << "send" << adecode.send(pkt) << endl;
for (;;)
{
int re = 0;
AVFrame* frame = adecode.receive(re);
if (re != 0)break;
}
}
if (!pkt)break;
}
Audio and video unpacking use the same class , Decode the various classes used , So two are instantiated decode, Take the video decoder as an example :
01. First instantiation :xdecode vdecode;
02. Then make a copy of the video parameters obtained by unpacking , Pass as a parameter to vdecode:vdecode.open(demux.CopyVPara()) << endl;
03. Read and package in the result of unpacking , Read one by one packet, The result is put in pkt in :AVPacket* pkt = demux.readfz();
04. What will be read out pkt Send it to the newly instantiated decoder vdecode decode :vdecode.send(pkt)
05. Put the result of the decoding thread in frame in :AVFrame* frame = vdecode.receive(re);
3.xdecode.cpp
bool xdecode::open(AVCodecParameters* pa)
{
// Fault tolerant processing
if (!pa)return false;//pa It's empty , Return error
close();
if (pa->codec_type == 1)
isAudio = true;
else
isAudio = false;
if(isAudio)
const AVCodec* codec = avcodec_find_decoder(pa->codec_id);
// The decoder number in the stream may not be found , Here we need to make a judgment to see if we can find the decoder
if (!codec)
{
avcodec_parameters_free(&pa);
std::cout << "can't find the codec id" <<pa->codec_id << endl;
return false;
}
if (!isAudio)
std::cout << " find the video codec id" << pa->codec_id << endl;
else
std::cout << " find the audio codec id" << pa->codec_id << endl;
mux.lock();
///03 Create decoder context
codeccontext = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codeccontext, pa);// The information obtained by unpacking is passed to the decoding context
avcodec_parameters_free(&pa);
// Eight thread decoding
codeccontext->thread_count = 8;
///05 Open decoder context
int re = avcodec_open2(codeccontext, 0, 0);// The second parameter is the decoder codec, But it has been passed in when creating the context , There is no need to pass it here
if (re != 0)
{
avcodec_parameters_free(&pa);
mux.unlock();
char buf[1024] = {
0 };
av_strerror(re, buf, sizeof(buf) - 1);// use buf Store error messages
std::cout << "open audio codec failed!" << buf << endl;
getchar();
return false;
}
std::cout << "video codec success!" << endl;
mux.unlock();
return true;
}
01. According to what was passed in codec_id Know what kind of decoder it is , According to this id No. find the corresponding decoder :
const AVCodec* codec = avcodec_find_decoder(pa->codec_id);
02. Pass a pointer to the video decoder into , Make room for the decoder context members of the class , And set the default parameters :
codeccontext = avcodec_alloc_context3(codec);
03. The unpacked information is passed to the decoder context , So far, unpacking the context has completed his mission , Can be released :avcodec_parameters_to_context(codeccontext, pa);
avcodec_parameters_free(&pa);
04. Open decoder context , The second parameter is the decoder codec, But it has been passed in when creating the context , There is no need to pass it here :
int re = avcodec_open2(codeccontext, 0, 0);
void xdecode::close()
{
mux.lock();
if (codeccontext)
{
avcodec_close(codeccontext);// Used in other functions codec All code snippets must be locked
avcodec_free_context(&codeccontext);
}
mux.unlock();
}
Decoder context codeccontext For out of class inaccessible , There will be close The function is encapsulated into a function
void xdecode::clear()// Clear the decoding buffer , Larger than the read buffer
{
mux.lock();
if (codeccontext)
avcodec_flush_buffers(codeccontext);
mux.unlock();
}
The data members in the class are closed and cleaned up codeccontext
bool xdecode::send(AVPacket* pkt)
{
if (!pkt || pkt->size <= 0 || !pkt->data)
{
cout << "a" << endl;
return false;
}
mux.lock();
if(!codeccontext)
{
mux.unlock();
cout << "b" << endl;
return false;
}
int re = avcodec_send_packet(codeccontext, pkt);// take pkt For the one opened in front codec
mux.unlock();
av_packet_free(&pkt);
if (re != 0)
{
cout << "c" << endl;
return false;
}
return true;
}
take pkt For the one opened in front codec:
int re = avcodec_send_packet(codeccontext, pkt);
AVFrame* xdecode::receive(int&r)
{
mux.lock();
if (!codeccontext)
{
mux.unlock();
return NULL;
}
AVFrame* frame = av_frame_alloc();// Open up space for receiving decoding queue output
r = avcodec_receive_frame(codeccontext, frame);
mux.unlock();
if (r != 0)
{
av_frame_free(&frame);// If the reception fails, the reception space will be opened in vain , To empty
return NULL;
}
cout <<"["<< frame->linesize[0]<<"]" << flush;
return frame;
}
01 Open up space for receiving decoding queue output :AVFrame* frame = av_frame_alloc();
02 Get... According to the decoder context frame:
r = avcodec_receive_frame(codeccontext, frame);
If the fault-tolerant interpretation fails , Is open up frame The space is useless , It needs to be emptied
4. result
Use flv File to test :
According to the printed a and c, There are two problems :
01. Read from unpacking packet There is a problem :
AVPacket* pkt = demux.readfz();
02 take pkt For the one opened in front codec failed :
int re = avcodec_send_packet(codeccontext, pkt);
What you see on the Internet and knowledge supplement :
Directly construct one of the key parameters obtained from the known information of the input stream AVCodecParameters, After such construction, it can also be decoded normally , But the decoded input stream has very strict restrictions :
Input pkt in data The data must be in 00 00 00 01 Initial data , such as ps flow rtsp rtp Data can be decoded normally , But if the open stream is flv MP4 When you wait, something goes wrong :No start code is found, Or keep returning AVERROR(EAGAIN)
NAL Full name Network Abstract Layer, Network abstraction layer .
(https://blog.csdn.net/ygm_linux/article/details/25562921)
stay H.264/AVC Video coding standard , The whole system framework is divided into two levels : Video coding level (VCL) And network abstraction (NAL). among , The former is responsible for effectively representing the content of video data , The latter is responsible for formatting the data and providing header information , To ensure that data is suitable for transmission on various channels and storage media . So every frame of data is one NAL unit (SPS And PPS With the exception of ). In practice H264 In data frame , Often the frame is preceded by 00 00 00 01 or 00 00 01 Separator , Generally speaking, the first frame data compiled by the encoder is PPS And SPS, Then for I frame ……
Here's the picture :
NALU Type is a sharp tool for us to judge the type of frame , From the official documents, as shown in the figure below :
With 00 00 00 01 The next byte after segmentation is NALU type , After converting it to binary data , The order of interpretation is from left to right , as follows :
(1) The first 1 A bit forbids a bit , The value is 1 There is a syntax error
(2) The first 2~3 Bit is the reference level
(3) The first 4~8 be for the purpose of nal Unit type
Such as the above 00000001 After the 67,68 as well as 65
among 0x67 The binary code of is :
0110 0111
4-8 by 00111, To decimal 7, Refer to the second picture :7 Corresponding sequence parameter set SPS, namely 0x67 Start until the next 00000001 The data between is SPS

Finally, it was changed , The problem is main Function , You should not judge the type in the decoder , Instead, it should be judged to read the package packet The type of , Put this judgment function in demux To realize :
int main(int argc, char *argv[])
{
xdemux demux;
const char* path = "E:\\ffmpeg\\test02.mp4";
cout << "demux.Open = " << demux.Open(path) << endl;
xdecode vdecode;// A class for audio and video unpacking , Decode each with its own
cout << "vdecode.open()" << vdecode.open(demux.CopyVPara()) << endl;
xdecode adecode;
cout << "adecode.open()" << adecode.open(demux.CopyAPara()) << endl;
for (;;)
{
AVPacket* pkt = demux.readfz();
if (demux.isvideo(pkt) == true)
{
vdecode.send(pkt);
AVFrame* frame = vdecode.receive();
}
else
{
adecode.send(pkt);
AVFrame* frame = adecode.receive();
}
if (!pkt)break;
}
QApplication a(argc, argv);
Xplay2 w;
w.show();
return a.exec();
}
AVPacket yes FFmpeg A very important data structure in , It saves knowledge after reuse , Data before decoding ( It's still compressed data ) And some additional information about these data , For example, the time stamp is displayed (pts)、 Decoding timestamp (dts)、 Data duration , The index of the media stream .
For video (Video) Come on ,AVPacket Usually contains a compressed Frame, And audio (Audio) It is possible to include multiple compressed Frame. also , One Packet It could be empty , Does not contain any compressed data , Contains only side data(side data, The container provides information about Packet Some additional information about . for example , Update some stream parameters at the end of coding ).
边栏推荐
- Implementation and debug of process hiding under x64
- Greed issues - Egypt scores
- Brush one question every day /537 Complex multiplication
- 阿裏雲開發板HaaS510報送設備屬性
- SystemC learning materials
- 阿里云开发板HaaS510报送设备属性
- 【mysql进阶】索引分类及索引优化方案(五)
- Lua common built-in functions
- Implementation of Ackermann function with simulated recursion
- Dial up and Ethernet
猜你喜欢

Paw advanced user guide

Go language functions as parameters of functions

Mémoire de l'examen d'entrée à l'université

Socket model of punctual atom stm32f429 core board

Alibaba cloud development board haas510 parses serial port JSON data and sends attributes

PostgreSQL14安装使用教程

Talk about the top 10 classic MySQL errors

什么是自动出价?它的优势是什么?

Crack WinRAR to ad pop-up window

阿里云开发板HaaS510响应UART串口指令
随机推荐
Reverse analysis from x86 to x64tips
注重点击,追求更多用户进入网站,可以选择什么出价策略?
动态搜索广告智能查找匹配关键字
Analysis of lua source code
Leetcode 2185. Counts the string containing the given prefix
Lua tvalue structure
[video lesson] a full set of tutorials on the design and production of Android studio Internet of things app -- all mastered during the National Day
如何使用android studio制作一个阿里云物联网APP
Why do Chinese programmers change jobs?
使用make方法创建slice切片的坑
Llvm 13.1 new pass plug-in form [for win]
Explanation of static and extern keywords
【mysql进阶】mysql索引数据结构的演变(四)
Display logs in the database through loganalyzer
肝了一个月的原创小袁个人博客项目开源啦(博客基本功能都有,还包含后台管理)
Alibaba cloud development board haas510 responds to UART serial port instructions
QA of some high frequency problems in oauth2 learning
Introduction to color coding format
Comparator summary
[advanced MySQL] evolution of MySQL index data structure (IV)