-
Notifications
You must be signed in to change notification settings - Fork 0
/
ffm_decoder.c
441 lines (393 loc) · 13.8 KB
/
ffm_decoder.c
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/*
* ffm_decoder.c
* ffmpeg 的h264解码库
*/
#include "ffm_decoder.h"
#include "h264_decoder.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixfmt.h"
#include "libswscale/swscale.h"
//缓存的时戳的最大个数
#define MAX_TIMESTAMP_COUNT 64
typedef struct __TIMESTAMP_ST
{
int32_t used_flg;
uint32_t timestamp;
}TIMESTAMP_ST;
//解码库的私有数据结构体
typedef struct __FFM_DEOCDER_ST
{
AVCodec *h264_codec;
AVCodecContext *h264_codec_ctx;
AVFrame *h264_frame;
AVPacket h264_avpkt;
struct SwsContext *sws_ctx; //图片格式转换句柄,保证给上层的数据都是YUV420p
enum AVPixelFormat src_fmt; //解码器输出的图片格式,如果不等于AV_PIX_FMT_YUV420P则会进行格式转换。
int32_t src_width; //解码器输出的图片的宽度
int32_t src_height; //解码器输出的图片的高度
uint8_t *yuv_buf; //有图片格式转换时临时使用的缓冲区
int32_t buf_len; //yuv_buf的长度
uint8_t *sws_data[LIBV_NUM_DATA_POINTERS]; //转换后的临时输出,内存使用yuv_buf
int32_t sws_linesize[LIBV_NUM_DATA_POINTERS]; //转换后的临时输出
TIMESTAMP_ST timestamps[MAX_TIMESTAMP_COUNT]; //环形数据结构
int32_t ts_start; //起始下标
int32_t ts_end; //结束下标
}FFM_DEOCDER_ST;
//用于解码器图片输出格式不为420p的情况下,转化为420p,下面是转换临时缓冲区长度,暂时定为4K。
static const int32_t G_FMT_SWS_BUF_LEN = 1920 * 1080 * 4 + 32;
static void ffm_release(H264_DECODER_TH *pdecth)
{
if (NULL == pdecth)
{
elog("ffm_release:input is error!");
return ;
}
FFM_DEOCDER_ST *pffm = (FFM_DEOCDER_ST *)pdecth->_private_data;
if (pffm)
{
avcodec_close(pffm->h264_codec_ctx);
av_free(pffm->h264_codec_ctx);
av_frame_free(&(pffm->h264_frame));
if (pffm->sws_ctx != NULL)
{
sws_freeContext(pffm->sws_ctx);
}
if (pffm->yuv_buf != NULL)
{
free(pffm->yuv_buf);
}
free(pffm);
}
}
//这两个时戳处理函数暂时不用
//static void ffm_add_timestamp(FFM_DEOCDER_ST *pffm, uint32_t ts)
//{
// if ((pffm->ts_end >= MAX_TIMESTAMP_COUNT) || (pffm->ts_end < 0))
// {
// elog("timestamps index[end:%d] is error!initial all.", pffm->ts_end);
// pffm->ts_end = 0;
// pffm->ts_start = 0;
// memset(pffm->timestamps, 0, sizeof(pffm->timestamps));
// }
// if (pffm->timestamps[pffm->ts_end].used_flg == 0)
// {
// pffm->timestamps[pffm->ts_end].used_flg = 1;
// pffm->timestamps[pffm->ts_end].timestamp = ts;
// pffm->ts_end += 1;
// if (pffm->ts_end >= MAX_TIMESTAMP_COUNT)
// {
// pffm->ts_end = 0;
// }
// }
// else
// {
// elog("ffmdeocer:there is no enough timestamp buf for add.");
// }
//}
//
//static uint32_t ffm_pop_timestamp(FFM_DEOCDER_ST *pffm)
//{
// uint32_t ts = 0;
//
// if ((pffm->ts_start >= MAX_TIMESTAMP_COUNT) || (pffm->ts_start < 0))
// {
// elog("timestamps index[ts_start:%d] is error!initial all.", pffm->ts_end);
// pffm->ts_end = 0;
// pffm->ts_start = 0;
// memset(pffm->timestamps, 0, sizeof(pffm->timestamps));
// }
//
// if (pffm->timestamps[pffm->ts_start].used_flg != 0)
// {
// pffm->timestamps[pffm->ts_start].used_flg = 0;
// ts = pffm->timestamps[pffm->ts_start].timestamp;
// pffm->timestamps[pffm->ts_start].timestamp = 0;
// pffm->ts_start += 1;
// if (pffm->ts_start >= MAX_TIMESTAMP_COUNT)
// {
// pffm->ts_start = 0;
// }
// return ts;
// }
// else
// {
// wlog("ffmdeocer:The start timestamp not used.");
// }
// return 0;
//}
//将解码器的输出由其他格式转化为yuv420p,成功返回0,失败返回-1,转换后的输出保存在:pffm->sws_data和pffm->sws_linesize
static int32_t ffm_sws_decoder_output_pic_to_yuv420p(FFM_DEOCDER_ST *pffm, AVFrame *h264_frame)
{
int32_t yuv_len = 0;
if ((NULL == pffm) || (h264_frame == NULL))
{
elog("ffm_sws_decoder_output_pic_to_yuv420p:input is error!");
return -1;
}
if (pffm->sws_ctx != NULL)
{
if ((pffm->src_fmt != h264_frame->format) || (pffm->src_height != h264_frame->height)
|| (pffm->src_width != h264_frame->width))//原先申请的转换器和目前的不匹配,重新申请。主要考虑视频流的格式,高宽会改变
{
sws_freeContext(pffm->sws_ctx); //先释放。
pffm->sws_ctx = NULL;
pffm->sws_ctx = sws_getContext(h264_frame->width, h264_frame->height, h264_frame->format,
h264_frame->width, h264_frame->height, AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (pffm->sws_ctx == NULL)
{
elog("decoder return form is not yuv420p, switch but sws_getContext return NULL!");
return -1;
}
}
}
else
{
pffm->sws_ctx = sws_getContext(h264_frame->width, h264_frame->height, h264_frame->format,
h264_frame->width, h264_frame->height, AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (pffm->sws_ctx == NULL)
{
elog("decoder return form is not yuv420p, switch but sws_getContext return NULL!");
return -1;
}
}
//申请成功,则保存参数
pffm->src_fmt = h264_frame->format;
pffm->src_height = h264_frame->height;
pffm->src_width = h264_frame->width;
//设置yuv 420的数据,首先判断缓冲区释放足够。
yuv_len = h264_frame->height * h264_frame->width;
if ((yuv_len * 3 /2) > pffm->buf_len)
{
wlog("switch decoder output pic,but buf is not long enough!");
return -1;
}
pffm->sws_data[0] = pffm->yuv_buf;
pffm->sws_data[1] = pffm->sws_data[0] + yuv_len;
pffm->sws_data[2] = pffm->sws_data[1] + yuv_len / 4 ;
pffm->sws_linesize[0] = h264_frame->width;
pffm->sws_linesize[1] = pffm->sws_linesize[2] = h264_frame->width>>1;
sws_scale(pffm->sws_ctx, (const uint8_t * const*)h264_frame->data,
h264_frame->linesize, 0, h264_frame->height, pffm->sws_data, pffm->sws_linesize);
return 0;
}
static int32_t ffm_decode_video(H264_DECODER_TH *pdecth, FRAME_PIC_DATA *pout_pic,
int32_t *got_picture_ptr, const H264_NAL_DATA *pnal)
{
int32_t len = 0;
AVFrame *h264_frame = NULL;
int32_t i = 0;
if ((NULL == pdecth) || (pout_pic == NULL) || (got_picture_ptr == NULL) || (pnal == NULL))
{
elog("ffm_decode_video:input is error!");
return -1;
}
FFM_DEOCDER_ST *pffm = (FFM_DEOCDER_ST *)pdecth->_private_data;
if (NULL == pffm)
{
elog("H264_DECODER_TH private_data is NULL!");
return -1;
}
pffm->h264_avpkt.size = pnal->data_size;
pffm->h264_avpkt.data = pnal->data_buf;
pffm->h264_avpkt.pts = pnal->timestamp;
pffm->h264_avpkt.dts = pnal->timestamp;
h264_frame = pffm->h264_frame;
len = avcodec_decode_video2(pffm->h264_codec_ctx, h264_frame, got_picture_ptr, &(pffm->h264_avpkt));
if (len < 0)
{
// elog("Error while decoding frame . len[%d] ", len);//这里不返回,还有看看是否有帧输出:没有帧是经常会输出负值,并打印错误。这里先注释,后面看看最新版本是否解决此问题
}
else //如果没有失败,则记录时戳
{
// ffm_add_timestamp(pffm, pnal->timestamp);
}
if (*got_picture_ptr)
{
// printf("===================return timestamp:%d,%d,%d\n", h264_frame->pts, h264_frame->pkt_pts, h264_frame->pkt_dts);
pout_pic->pic_type = libv_get_pic_type_by_ffm_type(h264_frame->pict_type);
pout_pic->key_frame = h264_frame->key_frame;
pout_pic->quality = h264_frame->quality;
pout_pic->width = h264_frame->width;
pout_pic->height = h264_frame->height;
pout_pic->timestamp = h264_frame->pkt_dts; //不用ffm_pop_timestamp(pffm);,直接使用解码器输出。
if (h264_frame->format == AV_PIX_FMT_YUV420P) //目前遇到的情况只有i420,如果遇到花屏或其他,可以在这里修改
{
for (i = 0; (i < LIBV_NUM_DATA_POINTERS) && (i < AV_NUM_DATA_POINTERS); i++)
{
pout_pic->data[i] = h264_frame->data[i];
pout_pic->linesize[i] = h264_frame->linesize[i];
}
}
else
{
//如果格式不对,则进行转换:
if (0 == ffm_sws_decoder_output_pic_to_yuv420p(pffm, h264_frame))
{
for (i = 0; (i < LIBV_NUM_DATA_POINTERS); i++)
{
pout_pic->data[i] = pffm->sws_data[i];
pout_pic->linesize[i] = pffm->sws_linesize[i];
}
}
else
{
wlog("switch deocder output pic from [%d] to yuv420p is error!", h264_frame->format);
return -1;
}
}
pout_pic->pic_format = PIC_FMT_YUV_I420;
}
return len;
}
static int32_t ffm_decode_video2(H264_DECODER_TH *pdecth, FRAME_PIC_DATA *pout_pic,
int32_t *got_picture_ptr, const H264_NAL_DATA *pnal)
{
int32_t len = 0;
AVFrame *h264_frame = NULL;
int32_t i = 0;
int ret = 0;
if ((NULL == pdecth) || (pout_pic == NULL) || (got_picture_ptr == NULL) || (pnal == NULL))
{
elog("ffm_decode_video:input is error!");
return -1;
}
FFM_DEOCDER_ST *pffm = (FFM_DEOCDER_ST *)pdecth->_private_data;
if (NULL == pffm)
{
elog("H264_DECODER_TH private_data is NULL!");
return -1;
}
pffm->h264_avpkt.size = pnal->data_size;
pffm->h264_avpkt.data = pnal->data_buf;
pffm->h264_avpkt.pts = pnal->timestamp;
pffm->h264_avpkt.dts = pnal->timestamp;
h264_frame = pffm->h264_frame;
ret = avcodec_send_packet(pffm->h264_codec_ctx, &(pffm->h264_avpkt));
ret = avcodec_receive_frame(pffm->h264_codec_ctx, h264_frame);
if(ret>=0){
*got_picture_ptr = 1;
}
if (*got_picture_ptr)
{
// printf("===================return timestamp:%d,%d,%d\n", h264_frame->pts, h264_frame->pkt_pts, h264_frame->pkt_dts);
pout_pic->pic_type = libv_get_pic_type_by_ffm_type(h264_frame->pict_type);
pout_pic->key_frame = h264_frame->key_frame;
pout_pic->quality = h264_frame->quality;
pout_pic->width = h264_frame->width;
pout_pic->height = h264_frame->height;
pout_pic->timestamp = h264_frame->pkt_dts; //不用ffm_pop_timestamp(pffm);,直接使用解码器输出。
if (h264_frame->format == AV_PIX_FMT_YUV420P) //目前遇到的情况只有i420,如果遇到花屏或其他,可以在这里修改
{
for (i = 0; (i < LIBV_NUM_DATA_POINTERS) && (i < AV_NUM_DATA_POINTERS); i++)
{
pout_pic->data[i] = h264_frame->data[i];
pout_pic->linesize[i] = h264_frame->linesize[i];
}
}
else
{
//如果格式不对,则进行转换:
if (0 == ffm_sws_decoder_output_pic_to_yuv420p(pffm, h264_frame))
{
for (i = 0; (i < LIBV_NUM_DATA_POINTERS); i++)
{
pout_pic->data[i] = pffm->sws_data[i];
pout_pic->linesize[i] = pffm->sws_linesize[i];
}
}
else
{
wlog("switch deocder output pic from [%d] to yuv420p is error!", h264_frame->format);
return -1;
}
}
pout_pic->pic_format = PIC_FMT_YUV_I420;
}
return len;
}
static int32_t ffm_init(H264_DECODER_TH *pdecth)
{
if (NULL == pdecth)
{
elog("ffm_init:input is error!");
return -1;
}
FFM_DEOCDER_ST *pffm = (FFM_DEOCDER_ST *)malloc(sizeof(FFM_DEOCDER_ST));
if (NULL == pffm)
{
elog("malloc memery is fail!");
return -1;
}
memset(pffm, 0, sizeof(FFM_DEOCDER_ST));
av_init_packet(&(pffm->h264_avpkt));
pffm->h264_codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (pffm->h264_codec == NULL)
{
elog("avcodec_find_decoder error!");
free(pffm);
return -1;
}
pffm->h264_codec_ctx = avcodec_alloc_context3(pffm->h264_codec);
if (pffm->h264_codec_ctx == NULL)
{
elog("avcodec_alloc_context3 error!\n");
free(pffm);
return -1;
}
int ret = avcodec_open2(pffm->h264_codec_ctx, pffm->h264_codec, NULL);
if (ret < 0)
{
elog("Could not open codec.%s",av_err2str(ret));
av_free(pffm->h264_codec_ctx);
free(pffm);
return -1;
}
pffm->h264_frame = av_frame_alloc();
if (pffm->h264_frame == NULL)
{
elog("Could not allocate video frame");
avcodec_close(pffm->h264_codec_ctx);
av_free(pffm->h264_codec_ctx);
free(pffm);
return -1;
}
pffm->sws_ctx = NULL;
pffm->src_fmt = AV_PIX_FMT_YUV420P;
pffm->src_width = 0;
pffm->src_height = 0;
pffm->buf_len = G_FMT_SWS_BUF_LEN;
pffm->yuv_buf = (uint8_t *)malloc(G_FMT_SWS_BUF_LEN);
if (NULL == pffm->yuv_buf)
{
elog("malloc yuv_buf MEMERY is fail: len is %d\n", G_FMT_SWS_BUF_LEN);
avcodec_close(pffm->h264_codec_ctx);
av_free(pffm->h264_codec_ctx);
av_frame_free(&(pffm->h264_frame));
free(pffm);
return -1;
}
pdecth->_private_data = (void *)pffm;
pdecth->decode_video = ffm_decode_video2;
return 0;
}
void ffm_decoder_init()
{
H264_DECODER_FACTORY *pfact = NULL;
//ffmpeg初始化函数
av_log_set_callback(ffm_av_log_callback);
// av_register_all();
// avcodec_register_all();
pfact = (H264_DECODER_FACTORY *)malloc(sizeof(H264_DECODER_FACTORY));
if (NULL == pfact)
{
elog("ffm_decoder_init:malloc memery is fail!");
exit(1);
}
pfact->id = H264_DECODER_ID_FFM;
pfact->init = ffm_init;
pfact->release = ffm_release;
h264_decoder_register(pfact);
}