-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathVideoDecoder.cpp
194 lines (169 loc) · 4.97 KB
/
VideoDecoder.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "stdafx.h"
#include "VideoDecoder.h"
#include "MediaQueue.h"
#include "trace.h"
#pragma unmanaged
/** Create a FrameInfo object.
* inline helper to create FrameInfo object
\param frame_size Default frame size
*/
inline FrameInfo* FrameNew(int frame_size = 4096)
{
FrameInfo* frame = (FrameInfo*)malloc(sizeof(FrameInfo)+frame_size);
if (frame == NULL)
return(NULL);
frame->pdata = (char *)frame + sizeof(FrameInfo);//new char[frame_size];
frame->frameHead.FrameLen = frame_size;
return(frame);
}
/** VideoDecoder Contrstructor.
* Allocates a AVFrame that will be reused by the decoder. Always
* initializes the ffmpeg decoding library, to accept a H264 frame
*/
CVideoDecoder::CVideoDecoder(void)
{
TRACE_INFO("Register codecs");
m_frame = avcodec_alloc_frame();
avcodec_register_all();
TRACE_INFO("Find codec");
m_codec = avcodec_find_decoder(CODEC_ID_H264);
if ( m_codec != NULL)
{
TRACE_INFO("Decoder found");
}else{
TRACE_ERROR("H264 Codec decoder not found");
}
TRACE_INFO("Allocate code context");
m_codecContext = avcodec_alloc_context3(m_codec);
m_codecContext->flags = 0;
TRACE_INFO("open codec");
int ret=avcodec_open2(m_codecContext, m_codec, NULL);
if (ret < 0)
{
TRACE_ERROR("Error opening codec ret=%d",ret);
}else{
TRACE_INFO("AV Codec found and opened");
}
if ( m_codecContext->codec_id == CODEC_ID_H264 )
m_codecContext->flags2 |= CODEC_FLAG2_CHUNKS;
}
/** VideoDecoder descructor.
Cleans up the ffmpeg environment and
frees the AVFrame
*/
CVideoDecoder::~CVideoDecoder()
{
TRACE_INFO("Cleaning up video sing");
if (m_frame!=NULL)
{
avcodec_close(m_codecContext);
av_free(m_frame);
}
m_frame = NULL;
if (m_codecContext!=NULL)
av_free(m_codecContext);
m_codecContext = NULL;
}
/** Decoder.
The supplied buffer should contain an H264 video frame, then DecodeFrame
will pass the buffer to the avcode_decode_video2 method. Once decoded we then
use the get_picture command to convert the frame to RGB24. The RGB24 buffer is
then used to create a FrameInfo object which is placed on our video queue.
\param pBuffer Memory buffer holding an H264 frame
\param size Size of the buffer
*/
FrameInfo* CVideoDecoder::DecodeFrame(unsigned char *pBuffer, int size)
{
FrameInfo *p_block=NULL;
uint8_t startCode4[] = {0x00, 0x00, 0x00, 0x01};
int got_frame = 0;
AVPacket packet;
//Initialize optional fields of a packet with default values.
av_init_packet(&packet);
//set the buffer and the size
packet.data = pBuffer;
packet.size = size;
while (packet.size > sizeof(startCode4))
{
//Decode the video frame of size avpkt->size from avpkt->data into picture.
int len = avcodec_decode_video2(m_codecContext, m_frame, &got_frame, &packet);
if(len<0)
{
TRACE_ERROR("Failed to decode video len=%d",len);
break;
}
//sometime we dont get the whole frame, so move
//forward and try again
if ( !got_frame )
{
packet.size -= len;
packet.data += len;
continue;
}
//allocate a working frame to store our rgb image
AVFrame * rgb = avcodec_alloc_frame();
if(rgb==NULL)
{
TRACE_ERROR("Failed to allocate new av frame");
return NULL;
}
//Allocate and return an SwsContext.
struct SwsContext * scale_ctx = sws_getContext(m_codecContext->width,
m_codecContext->height,
m_codecContext->pix_fmt,
m_codecContext->width,
m_codecContext->height,
PIX_FMT_BGR24,
SWS_BICUBIC,
NULL,
NULL,
NULL);
if (scale_ctx == NULL)
{
TRACE_ERROR("Failed to get context");
continue;
}
//Calculate the size in bytes that a picture of the given width and height would occupy if stored in the given picture format.
int numBytes = avpicture_get_size(PIX_FMT_RGB24,
m_codecContext->width,
m_codecContext->height);
try{
//create one of our FrameInfo objects
p_block = FrameNew(numBytes);
if(p_block==NULL){
//cleanup the working buffer
av_free(rgb);
sws_freeContext(scale_ctx);
scale_ctx=NULL;
return NULL;
}
//Fill our frame buffer with the rgb image
avpicture_fill((AVPicture*)rgb,
(uint8_t*)p_block->pdata,
PIX_FMT_RGB24,
m_codecContext->width,
m_codecContext->height);
//Scale the image slice in srcSlice and put the resulting scaled slice in the image in dst.
sws_scale(scale_ctx,
m_frame->data,
m_frame->linesize,
0,
m_codecContext->height,
rgb->data,
rgb->linesize);
//set the frame header to indicate rgb24
p_block->frameHead.FrameType = (long)(PIX_FMT_RGB24);
p_block->frameHead.TimeStamp = 0;
}
catch(...)
{
TRACE_ERROR("EXCEPTION: in afterGettingFrame1 ");
}
//cleanup the working buffer
av_free(rgb);
sws_freeContext(scale_ctx);
//we got our frame no its time to move on
break;
}
return p_block;
}