[FFmpeg-devel] [PATCH] opus/matroska: Adding support for End Trimming in demuxer/decoder

Vignesh Venkatasubramanian vigneshv at google.com
Fri Aug 30 20:25:12 CEST 2013


Implementing support for end trimming Opus in Matroska by making
use of the DiscardPadding value from the container and discarding
the samples accordingly. With this patch and its companion muxer
patch, we can ensure number of samples in == number of samples out
for Opus in Matroska.

Signed-off-by: Vignesh Venkatasubramanian <vigneshv at google.com>
---
 libavcodec/utils.c        | 21 +++++++++++++++++++++
 libavformat/matroskadec.c | 30 +++++++++++++++++++++++++-----
 2 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 0be9340..477a1a1 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -2111,6 +2111,7 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
     if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
         uint8_t *side;
         int side_size;
+        uint32_t discard_padding = 0;
         // copy to ensure we do not change avpkt
         AVPacket tmp = *avpkt;
         int did_split = av_packet_split_side_data(&tmp);
@@ -2145,6 +2146,7 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
             avctx->internal->skip_samples = AV_RL32(side);
             av_log(avctx, AV_LOG_DEBUG, "skip %d samples due to side data\n",
                    avctx->internal->skip_samples);
+            discard_padding = AV_RL32(side + 4);
         }
         if (avctx->internal->skip_samples && *got_frame_ptr) {
             if(frame->nb_samples <= avctx->internal->skip_samples){
@@ -2175,6 +2177,25 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
             }
         }
 
+        if (discard_padding > 0 && *got_frame_ptr) {
+            if (discard_padding == frame->nb_samples) {
+                *got_frame_ptr = 0;
+            } else {
+                if(avctx->pkt_timebase.num && avctx->sample_rate) {
+                    int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding,
+                                                   (AVRational){1, avctx->sample_rate},
+                                                   avctx->pkt_timebase);
+                    if (av_frame_get_pkt_duration(frame) >= diff_ts)
+                        av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts);
+                } else {
+                    av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n");
+                }
+                av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n",
+                       discard_padding, frame->nb_samples);
+                frame->nb_samples -= discard_padding;
+            }
+        }
+
         avctx->pkt = NULL;
         if (did_split) {
             av_packet_free_side_data(&tmp);
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 60f7a5a..e504871 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -290,6 +290,7 @@ typedef struct {
     EbmlBin  bin;
     uint64_t additional_id;
     EbmlBin  additional;
+    uint64_t discard_padding;
 } MatroskaBlock;
 
 static EbmlSyntax ebml_header[] = {
@@ -563,6 +564,7 @@ static EbmlSyntax matroska_blockgroup[] = {
     { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, {.n=matroska_blockadditions} },
     { MATROSKA_ID_SIMPLEBLOCK,    EBML_BIN,  0, offsetof(MatroskaBlock,bin) },
     { MATROSKA_ID_BLOCKDURATION,  EBML_UINT, 0, offsetof(MatroskaBlock,duration) },
+    { MATROSKA_ID_DISCARDPADDING, EBML_UINT, 0, offsetof(MatroskaBlock,discard_padding) },
     { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
     { MATROSKA_ID_CODECSTATE,     EBML_NONE },
     { 1,                          EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} },
@@ -2359,7 +2361,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
                                 uint8_t *data, int pkt_size,
                                 uint64_t timecode, uint64_t lace_duration,
                                 int64_t pos, int is_keyframe,
-                                uint8_t *additional, uint64_t additional_id, int additional_size)
+                                uint8_t *additional, uint64_t additional_id, int additional_size,
+                                uint64_t discard_padding)
 {
     MatroskaTrackEncoding *encodings = track->encodings.elem;
     uint8_t *pkt_data = data;
@@ -2422,6 +2425,21 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
         memcpy(side_data + 8, additional, additional_size);
     }
 
+    if (discard_padding) {
+        uint8_t *side_data = av_packet_new_side_data(pkt,
+                                                     AV_PKT_DATA_SKIP_SAMPLES,
+                                                     10);
+        if(side_data == NULL) {
+            av_free_packet(pkt);
+            av_free(pkt);
+            return AVERROR(ENOMEM);
+        }
+        AV_WL32(side_data, 0);
+        AV_WL32(side_data + 4, av_rescale_q(discard_padding,
+                                            (AVRational){1, 1000000000},
+                                            (AVRational){1, st->codec->sample_rate}));
+    }
+
     if (track->ms_compat)
         pkt->dts = timecode;
     else
@@ -2481,7 +2499,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
                                 int size, int64_t pos, uint64_t cluster_time,
                                 uint64_t block_duration, int is_keyframe,
                                 uint8_t *additional, uint64_t additional_id, int additional_size,
-                                int64_t cluster_pos)
+                                int64_t cluster_pos, uint64_t discard_padding)
 {
     uint64_t timecode = AV_NOPTS_VALUE;
     MatroskaTrack *track;
@@ -2593,7 +2611,8 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
             res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
                                       timecode, lace_duration,
                                       pos, !n? is_keyframe : 0,
-                                      additional, additional_id, additional_size);
+                                      additional, additional_id, additional_size,
+                                      discard_padding);
             if (res)
                 goto end;
         }
@@ -2660,7 +2679,8 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
                                        blocks[i].duration, is_keyframe,
                                        additional, blocks[i].additional_id,
                                        blocks[i].additional.size,
-                                       matroska->current_cluster_pos);
+                                       matroska->current_cluster_pos,
+                                       blocks[i].discard_padding);
         }
     }
 
@@ -2690,7 +2710,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
                                      blocks[i].bin.data, blocks[i].bin.size,
                                      blocks[i].bin.pos,  cluster.timecode,
                                      blocks[i].duration, is_keyframe, NULL, 0, 0,
-                                     pos);
+                                     pos, blocks[i].discard_padding);
         }
     ebml_free(matroska_cluster, &cluster);
     return res;
-- 
1.8.4



More information about the ffmpeg-devel mailing list