FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/bsf/dts2pts.c
Date: 2024-05-03 15:42:48
Exec Total Coverage
Lines: 0 281 0.0%
Functions: 0 14 0.0%
Branches: 0 171 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2022 James Almer
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * Derive PTS by reordering DTS from supported streams
24 */
25
26 #include "libavutil/avassert.h"
27 #include "libavutil/fifo.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/tree.h"
30
31 #include "bsf.h"
32 #include "bsf_internal.h"
33 #include "cbs.h"
34 #include "cbs_h264.h"
35 #include "h264_parse.h"
36 #include "h264_ps.h"
37
38 typedef struct DTS2PTSNode {
39 int64_t dts;
40 int64_t duration;
41 int poc;
42 int gop;
43 } DTS2PTSNode;
44
45 typedef struct DTS2PTSFrame {
46 AVPacket *pkt;
47 int poc;
48 int poc_diff;
49 int gop;
50 } DTS2PTSFrame;
51
52 typedef struct DTS2PTSH264Context {
53 H264POCContext poc;
54 SPS sps;
55 int poc_diff;
56 int last_poc;
57 int highest_poc;
58 int picture_structure;
59 } DTS2PTSH264Context;
60
61 typedef struct DTS2PTSContext {
62 struct AVTreeNode *root;
63 AVFifo *fifo;
64
65 // Codec specific function pointers and constants
66 int (*init)(AVBSFContext *ctx);
67 int (*filter)(AVBSFContext *ctx);
68 void (*flush)(AVBSFContext *ctx);
69 size_t fifo_size;
70
71 CodedBitstreamContext *cbc;
72 CodedBitstreamFragment au;
73
74 union {
75 DTS2PTSH264Context h264;
76 } u;
77
78 int nb_frame;
79 int gop;
80 int eof;
81 } DTS2PTSContext;
82
83 // AVTreeNode callbacks
84 static int cmp_insert(const void *key, const void *node)
85 {
86 int ret = ((const DTS2PTSNode *)key)->poc - ((const DTS2PTSNode *)node)->poc;
87 if (!ret)
88 ret = ((const DTS2PTSNode *)key)->gop - ((const DTS2PTSNode *)node)->gop;
89 return ret;
90 }
91
92 static int cmp_find(const void *key, const void *node)
93 {
94 const DTS2PTSFrame * key1 = key;
95 const DTS2PTSNode *node1 = node;
96 int ret = FFDIFFSIGN(key1->poc, node1->poc);
97 if (!ret)
98 ret = key1->gop - node1->gop;
99 return ret;
100 }
101
102 static int dec_poc(void *opaque, void *elem)
103 {
104 DTS2PTSNode *node = elem;
105 int dec = *(int *)opaque;
106 node->poc -= dec;
107 return 0;
108 }
109
110 static int free_node(void *opaque, void *elem)
111 {
112 DTS2PTSNode *node = elem;
113 av_free(node);
114 return 0;
115 }
116
117 // Shared functions
118 static int alloc_and_insert_node(AVBSFContext *ctx, int64_t ts, int64_t duration,
119 int poc, int poc_diff, int gop)
120 {
121 DTS2PTSContext *s = ctx->priv_data;
122 for (int i = 0; i < poc_diff; i++) {
123 struct AVTreeNode *node = av_tree_node_alloc();
124 DTS2PTSNode *poc_node, *ret;
125 if (!node)
126 return AVERROR(ENOMEM);
127 poc_node = av_malloc(sizeof(*poc_node));
128 if (!poc_node) {
129 av_free(node);
130 return AVERROR(ENOMEM);
131 }
132 if (i && ts != AV_NOPTS_VALUE)
133 ts += duration / poc_diff;
134 *poc_node = (DTS2PTSNode) { ts, duration, poc++, gop };
135 ret = av_tree_insert(&s->root, poc_node, cmp_insert, &node);
136 if (ret && ret != poc_node) {
137 *ret = *poc_node;
138 av_free(poc_node);
139 av_free(node);
140 }
141 }
142 return 0;
143 }
144
145 // H.264
146 static const CodedBitstreamUnitType h264_decompose_unit_types[] = {
147 H264_NAL_SPS,
148 H264_NAL_PPS,
149 H264_NAL_IDR_SLICE,
150 H264_NAL_SLICE,
151 };
152
153 static int h264_init(AVBSFContext *ctx)
154 {
155 DTS2PTSContext *s = ctx->priv_data;
156 DTS2PTSH264Context *h264 = &s->u.h264;
157
158 s->cbc->decompose_unit_types = h264_decompose_unit_types;
159 s->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(h264_decompose_unit_types);
160
161 s->nb_frame = -(ctx->par_in->video_delay << 1);
162 h264->last_poc = h264->highest_poc = INT_MIN;
163
164 return 0;
165 }
166
167 static int get_mmco_reset(const H264RawSliceHeader *header)
168 {
169 if (header->nal_unit_header.nal_ref_idc == 0 ||
170 !header->adaptive_ref_pic_marking_mode_flag)
171 return 0;
172
173 for (int i = 0; i < H264_MAX_MMCO_COUNT; i++) {
174 if (header->mmco[i].memory_management_control_operation == 0)
175 return 0;
176 else if (header->mmco[i].memory_management_control_operation == 5)
177 return 1;
178 }
179
180 return 0;
181 }
182
183 static int h264_queue_frame(AVBSFContext *ctx, AVPacket *pkt, int poc, int *queued)
184 {
185 DTS2PTSContext *s = ctx->priv_data;
186 DTS2PTSH264Context *h264 = &s->u.h264;
187 DTS2PTSFrame frame;
188 int poc_diff, ret;
189
190 poc_diff = (h264->picture_structure == 3) + 1;
191 if (h264->sps.frame_mbs_only_flag && h264->poc_diff)
192 poc_diff = FFMIN(poc_diff, h264->poc_diff);
193 if (poc < 0) {
194 av_tree_enumerate(s->root, &poc_diff, NULL, dec_poc);
195 s->nb_frame -= poc_diff;
196 }
197 // Check if there was a POC reset (Like an IDR slice)
198 if (s->nb_frame > h264->highest_poc) {
199 s->nb_frame = 0;
200 s->gop = (s->gop + 1) % s->fifo_size;
201 h264->highest_poc = h264->last_poc;
202 }
203
204 ret = alloc_and_insert_node(ctx, pkt->dts, pkt->duration, s->nb_frame, poc_diff, s->gop);
205 if (ret < 0)
206 return ret;
207 av_log(ctx, AV_LOG_DEBUG, "Queueing frame with POC %d, GOP %d, dts %"PRId64"\n",
208 poc, s->gop, pkt->dts);
209 s->nb_frame += poc_diff;
210
211 // Add frame to output FIFO only once
212 if (*queued)
213 return 0;
214
215 frame = (DTS2PTSFrame) { pkt, poc, poc_diff, s->gop };
216 ret = av_fifo_write(s->fifo, &frame, 1);
217 av_assert2(ret >= 0);
218 *queued = 1;
219
220 return 0;
221 }
222
223 static int h264_filter(AVBSFContext *ctx)
224 {
225 DTS2PTSContext *s = ctx->priv_data;
226 DTS2PTSH264Context *h264 = &s->u.h264;
227 CodedBitstreamFragment *au = &s->au;
228 AVPacket *in;
229 int output_picture_number = INT_MIN;
230 int field_poc[2];
231 int queued = 0, ret;
232
233 ret = ff_bsf_get_packet(ctx, &in);
234 if (ret < 0)
235 return ret;
236
237 ret = ff_cbs_read_packet(s->cbc, au, in);
238 if (ret < 0) {
239 av_log(ctx, AV_LOG_WARNING, "Failed to parse access unit.\n");
240 goto fail;
241 }
242
243 for (int i = 0; i < au->nb_units; i++) {
244 CodedBitstreamUnit *unit = &au->units[i];
245
246 switch (unit->type) {
247 case H264_NAL_IDR_SLICE:
248 h264->poc.prev_frame_num = 0;
249 h264->poc.prev_frame_num_offset = 0;
250 h264->poc.prev_poc_msb =
251 h264->poc.prev_poc_lsb = 0;
252 // fall-through
253 case H264_NAL_SLICE: {
254 const H264RawSlice *slice = unit->content;
255 const H264RawSliceHeader *header = &slice->header;
256 const CodedBitstreamH264Context *cbs_h264 = s->cbc->priv_data;
257 const H264RawSPS *sps = cbs_h264->active_sps;
258 int got_reset;
259
260 if (!sps) {
261 av_log(ctx, AV_LOG_ERROR, "No active SPS for a slice\n");
262 goto fail;
263 }
264 // Initialize the SPS struct with the fields ff_h264_init_poc() cares about
265 h264->sps.frame_mbs_only_flag = sps->frame_mbs_only_flag;
266 h264->sps.log2_max_frame_num = sps->log2_max_frame_num_minus4 + 4;
267 h264->sps.poc_type = sps->pic_order_cnt_type;
268 h264->sps.log2_max_poc_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
269 h264->sps.offset_for_non_ref_pic = sps->offset_for_non_ref_pic;
270 h264->sps.offset_for_top_to_bottom_field = sps->offset_for_top_to_bottom_field;
271 h264->sps.poc_cycle_length = sps->num_ref_frames_in_pic_order_cnt_cycle;
272 for (int i = 0; i < h264->sps.poc_cycle_length; i++)
273 h264->sps.offset_for_ref_frame[i] = sps->offset_for_ref_frame[i];
274
275 h264->picture_structure = sps->frame_mbs_only_flag ? 3 :
276 (header->field_pic_flag ?
277 header->field_pic_flag + header->bottom_field_flag : 3);
278
279 h264->poc.frame_num = header->frame_num;
280 h264->poc.poc_lsb = header->pic_order_cnt_lsb;
281 h264->poc.delta_poc_bottom = header->delta_pic_order_cnt_bottom;
282 h264->poc.delta_poc[0] = header->delta_pic_order_cnt[0];
283 h264->poc.delta_poc[1] = header->delta_pic_order_cnt[1];
284
285 field_poc[0] = field_poc[1] = INT_MAX;
286 ret = ff_h264_init_poc(field_poc, &output_picture_number, &h264->sps,
287 &h264->poc, h264->picture_structure,
288 header->nal_unit_header.nal_ref_idc);
289 if (ret < 0) {
290 av_log(ctx, AV_LOG_ERROR, "ff_h264_init_poc() failure\n");
291 goto fail;
292 }
293
294 got_reset = get_mmco_reset(header);
295 h264->poc.prev_frame_num = got_reset ? 0 : h264->poc.frame_num;
296 h264->poc.prev_frame_num_offset = got_reset ? 0 : h264->poc.frame_num_offset;
297 if (header->nal_unit_header.nal_ref_idc != 0) {
298 h264->poc.prev_poc_msb = got_reset ? 0 : h264->poc.poc_msb;
299 if (got_reset)
300 h264->poc.prev_poc_lsb = h264->picture_structure == 2 ? 0 : field_poc[0];
301 else
302 h264->poc.prev_poc_lsb = h264->poc.poc_lsb;
303 }
304
305 if (output_picture_number != h264->last_poc) {
306 if (h264->last_poc != INT_MIN) {
307 int64_t diff = FFABS(h264->last_poc - (int64_t)output_picture_number);
308
309 if ((output_picture_number < 0) && !h264->last_poc)
310 h264->poc_diff = 0;
311 else if (FFABS((int64_t)output_picture_number) < h264->poc_diff) {
312 diff = FFABS(output_picture_number);
313 h264->poc_diff = 0;
314 }
315 if ((!h264->poc_diff || (h264->poc_diff > diff)) && diff <= INT_MAX) {
316 h264->poc_diff = diff;
317 if (h264->poc_diff == 1 && h264->sps.frame_mbs_only_flag) {
318 av_tree_enumerate(s->root, &h264->poc_diff, NULL, dec_poc);
319 s->nb_frame -= 2;
320 }
321 }
322 }
323 h264->last_poc = output_picture_number;
324 h264->highest_poc = FFMAX(h264->highest_poc, output_picture_number);
325
326 ret = h264_queue_frame(ctx, in, output_picture_number, &queued);
327 if (ret < 0)
328 goto fail;
329 }
330 break;
331 }
332 default:
333 break;
334 }
335 }
336
337 if (output_picture_number == INT_MIN) {
338 av_log(ctx, AV_LOG_ERROR, "No slices in access unit\n");
339 ret = AVERROR_INVALIDDATA;
340 goto fail;
341 }
342
343 ret = 0;
344 fail:
345 ff_cbs_fragment_reset(au);
346 if (!queued)
347 av_packet_free(&in);
348
349 return ret;
350 }
351
352 static void h264_flush(AVBSFContext *ctx)
353 {
354 DTS2PTSContext *s = ctx->priv_data;
355 DTS2PTSH264Context *h264 = &s->u.h264;
356
357 memset(&h264->sps, 0, sizeof(h264->sps));
358 memset(&h264->poc, 0, sizeof(h264->poc));
359 s->nb_frame = -(ctx->par_in->video_delay << 1);
360 h264->last_poc = h264->highest_poc = INT_MIN;
361 }
362
363 // Core functions
364 static const struct {
365 enum AVCodecID id;
366 int (*init)(AVBSFContext *ctx);
367 int (*filter)(AVBSFContext *ctx);
368 void (*flush)(AVBSFContext *ctx);
369 size_t fifo_size;
370 } func_tab[] = {
371 { AV_CODEC_ID_H264, h264_init, h264_filter, h264_flush, H264_MAX_DPB_FRAMES * 2 * 2 },
372 };
373
374 static int dts2pts_init(AVBSFContext *ctx)
375 {
376 DTS2PTSContext *s = ctx->priv_data;
377 CodedBitstreamFragment *au = &s->au;
378 int i, ret;
379
380 for (i = 0; i < FF_ARRAY_ELEMS(func_tab); i++) {
381 if (func_tab[i].id == ctx->par_in->codec_id) {
382 s->init = func_tab[i].init;
383 s->filter = func_tab[i].filter;
384 s->flush = func_tab[i].flush;
385 s->fifo_size = func_tab[i].fifo_size;
386 break;
387 }
388 }
389 if (i == FF_ARRAY_ELEMS(func_tab))
390 return AVERROR_BUG;
391 av_assert0(s->filter && s->fifo_size);
392
393 s->fifo = av_fifo_alloc2(s->fifo_size, sizeof(DTS2PTSFrame), 0);
394 if (!s->fifo)
395 return AVERROR(ENOMEM);
396
397 ret = ff_cbs_init(&s->cbc, ctx->par_in->codec_id, ctx);
398 if (ret < 0)
399 return ret;
400
401 if (s->init) {
402 ret = s->init(ctx);
403 if (ret < 0)
404 return ret;
405 }
406
407 if (!ctx->par_in->extradata_size)
408 return 0;
409
410 ret = ff_cbs_read_extradata(s->cbc, au, ctx->par_in);
411 if (ret < 0)
412 av_log(ctx, AV_LOG_WARNING, "Failed to parse extradata.\n");
413
414 ff_cbs_fragment_reset(au);
415
416 return 0;
417 }
418
419 static int dts2pts_filter(AVBSFContext *ctx, AVPacket *out)
420 {
421 DTS2PTSContext *s = ctx->priv_data;
422 DTS2PTSNode *poc_node = NULL, *next[2] = { NULL, NULL };
423 DTS2PTSFrame frame;
424 int ret;
425
426 // Fill up the FIFO and POC tree
427 while (!s->eof && av_fifo_can_write(s->fifo)) {
428 ret = s->filter(ctx);
429 if (ret < 0) {
430 if (ret != AVERROR_EOF)
431 return ret;
432 s->eof = 1;
433 }
434 }
435
436 if (!av_fifo_can_read(s->fifo))
437 return AVERROR_EOF;
438
439 // Fetch a packet from the FIFO
440 ret = av_fifo_read(s->fifo, &frame, 1);
441 av_assert2(ret >= 0);
442 av_packet_move_ref(out, frame.pkt);
443 av_packet_free(&frame.pkt);
444
445 // Search the timestamp for the requested POC and set PTS
446 poc_node = av_tree_find(s->root, &frame, cmp_find, (void **)next);
447 if (!poc_node) {
448 poc_node = next[1];
449 if (!poc_node || poc_node->poc != frame.poc)
450 poc_node = next[0];
451 }
452 if (poc_node && poc_node->poc == frame.poc) {
453 out->pts = poc_node->dts;
454 if (!s->eof) {
455 // Remove the found entry from the tree
456 DTS2PTSFrame dup = (DTS2PTSFrame) { NULL, frame.poc + 1, frame.poc_diff, frame.gop };
457 for (; dup.poc_diff > 0; dup.poc++, dup.poc_diff--) {
458 struct AVTreeNode *node = NULL;
459 if (!poc_node || poc_node->dts != out->pts)
460 continue;
461 av_tree_insert(&s->root, poc_node, cmp_insert, &node);
462 av_free(poc_node);
463 av_free(node);
464 poc_node = av_tree_find(s->root, &dup, cmp_find, NULL);
465 }
466 }
467 } else if (s->eof && frame.poc > INT_MIN) {
468 DTS2PTSFrame dup = (DTS2PTSFrame) { NULL, frame.poc - 1, frame.poc_diff, frame.gop };
469 poc_node = av_tree_find(s->root, &dup, cmp_find, NULL);
470 if (poc_node && poc_node->poc == dup.poc) {
471 out->pts = poc_node->dts;
472 if (out->pts != AV_NOPTS_VALUE)
473 out->pts += poc_node->duration;
474 ret = alloc_and_insert_node(ctx, out->pts, out->duration,
475 frame.poc, frame.poc_diff, frame.gop);
476 if (ret < 0) {
477 av_packet_unref(out);
478 return ret;
479 }
480 if (!ret)
481 av_log(ctx, AV_LOG_DEBUG, "Queueing frame for POC %d, GOP %d, dts %"PRId64", "
482 "generated from POC %d, GOP %d, dts %"PRId64", duration %"PRId64"\n",
483 frame.poc, frame.gop, out->pts,
484 poc_node->poc, poc_node->gop, poc_node->dts, poc_node->duration);
485 } else
486 av_log(ctx, AV_LOG_WARNING, "No timestamp for POC %d in tree\n", frame.poc);
487 } else
488 av_log(ctx, AV_LOG_WARNING, "No timestamp for POC %d in tree\n", frame.poc);
489 av_log(ctx, AV_LOG_DEBUG, "Returning frame for POC %d, GOP %d, dts %"PRId64", pts %"PRId64"\n",
490 frame.poc, frame.gop, out->dts, out->pts);
491
492 return 0;
493 }
494
495 static void dts2pts_flush(AVBSFContext *ctx)
496 {
497 DTS2PTSContext *s = ctx->priv_data;
498 DTS2PTSFrame frame;
499
500 if (s->flush)
501 s->flush(ctx);
502 s->eof = 0;
503 s->gop = 0;
504
505 while (s->fifo && av_fifo_read(s->fifo, &frame, 1) >= 0)
506 av_packet_free(&frame.pkt);
507
508 av_tree_enumerate(s->root, NULL, NULL, free_node);
509 av_tree_destroy(s->root);
510 s->root = NULL;
511
512 ff_cbs_fragment_reset(&s->au);
513 if (s->cbc)
514 ff_cbs_flush(s->cbc);
515 }
516
517 static void dts2pts_close(AVBSFContext *ctx)
518 {
519 DTS2PTSContext *s = ctx->priv_data;
520
521 dts2pts_flush(ctx);
522
523 av_fifo_freep2(&s->fifo);
524 ff_cbs_fragment_free(&s->au);
525 ff_cbs_close(&s->cbc);
526 }
527
528 static const enum AVCodecID dts2pts_codec_ids[] = {
529 AV_CODEC_ID_H264,
530 AV_CODEC_ID_NONE,
531 };
532
533 const FFBitStreamFilter ff_dts2pts_bsf = {
534 .p.name = "dts2pts",
535 .p.codec_ids = dts2pts_codec_ids,
536 .priv_data_size = sizeof(DTS2PTSContext),
537 .init = dts2pts_init,
538 .flush = dts2pts_flush,
539 .close = dts2pts_close,
540 .filter = dts2pts_filter,
541 };
542