Re: [libav-devel] [PATCH] mov: Implement support for multiple sample description tables

2016-06-16 Thread Vittorio Giovara
On Wed, Jun 15, 2016 at 3:24 PM, Vittorio Giovara
 wrote:
> Store data from each stsd in a separate extradata buffer, keep track of
> the stsc index for read and seek operations, switch buffers when the
> index differs. Decoder is notified with an AV_PKT_DATA_NEW_EXTRADATA
> packet side data.
>
> Since H264 supports this notification, and can be reset midstream, enable
> this feature only for multiple avcC's. All other stsd types (such as
> hvc1 and hev1) need decoder-side changes, so they are left disabled for
> now.
>
> This is implemented only in non-fragmented MOVs.
>
> Signed-off-by: Vittorio Giovara 
> ---
> Squashed 5/5 in this one, moved extradata change to a separate function.
> Vittorio

Ok'd by Luca.
-- 
Vittorio
___
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel


[libav-devel] [PATCH] mov: Implement support for multiple sample description tables

2016-06-15 Thread Vittorio Giovara
Store data from each stsd in a separate extradata buffer, keep track of
the stsc index for read and seek operations, switch buffers when the
index differs. Decoder is notified with an AV_PKT_DATA_NEW_EXTRADATA
packet side data.

Since H264 supports this notification, and can be reset midstream, enable
this feature only for multiple avcC's. All other stsd types (such as
hvc1 and hev1) need decoder-side changes, so they are left disabled for
now.

This is implemented only in non-fragmented MOVs.

Signed-off-by: Vittorio Giovara 
---
Squashed 5/5 in this one, moved extradata change to a separate function.
Vittorio

 libavformat/isom.h |   8 
 libavformat/mov.c  | 123 ++---
 2 files changed, 125 insertions(+), 6 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index aec623b..75aa70b 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -105,6 +105,8 @@ typedef struct MOVStreamContext {
 MOVStts *ctts_data;
 unsigned int stsc_count;
 MOVStsc *stsc_data;
+int stsc_index;
+int stsc_sample;
 unsigned int stps_count;
 unsigned *stps_data;  ///< partial sync sample for mpeg-2 open gop
 int ctts_index;
@@ -137,6 +139,12 @@ typedef struct MOVStreamContext {
 unsigned int rap_group_count;
 MOVSbgp *rap_group;
 
+/** extradata array (and size) for multiple stsd */
+uint8_t **extradata;
+int *extradata_size;
+int last_stsd_index;
+int stsd_count;
+
 int32_t *display_matrix;
 } MOVStreamContext;
 
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 125919f..70c6b12 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1771,8 +1771,7 @@ static int mov_skip_multiple_stsd(MOVContext *c, 
AVIOContext *pb,
 int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format);
 
 if (codec_tag &&
-(codec_tag == AV_RL32("avc1") ||
- codec_tag == AV_RL32("hvc1") ||
+(codec_tag == AV_RL32("hvc1") ||
  codec_tag == AV_RL32("hev1") ||
  (codec_tag != format &&
   (c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id
@@ -1857,6 +1856,19 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext 
*pb, int entries)
 return ret;
 } else if (a.size > 0)
 avio_skip(pb, a.size);
+
+if (sc->extradata) {
+int extra_size = st->codecpar->extradata_size;
+
+/* Move the current stream extradata to the stream context one. */
+sc->extradata_size[pseudo_stream_id] = extra_size;
+sc->extradata[pseudo_stream_id] = av_malloc(extra_size + 
AV_INPUT_BUFFER_PADDING_SIZE);
+if (!sc->extradata[pseudo_stream_id])
+return AVERROR(ENOMEM);
+memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, 
extra_size);
+av_freep(>codecpar->extradata);
+st->codecpar->extradata_size = 0;
+}
 }
 
 if (pb->eof_reached)
@@ -1867,13 +1879,41 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext 
*pb, int entries)
 
 static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
-int entries;
+AVStream *st;
+MOVStreamContext *sc;
+int ret;
+
+if (c->fc->nb_streams < 1)
+return 0;
+st = c->fc->streams[c->fc->nb_streams - 1];
+sc = st->priv_data;
 
 avio_r8(pb); /* version */
 avio_rb24(pb); /* flags */
-entries = avio_rb32(pb);
+sc->stsd_count = avio_rb32(pb); /* entries */
+
+/* Prepare space for hosting multiple extradata. */
+sc->extradata = av_mallocz_array(sc->stsd_count, sizeof(*sc->extradata));
+if (!sc->extradata)
+return AVERROR(ENOMEM);
 
-return ff_mov_read_stsd_entries(c, pb, entries);
+sc->extradata_size = av_mallocz_array(sc->stsd_count, 
sizeof(sc->extradata_size));
+if (!sc->extradata_size)
+return AVERROR(ENOMEM);
+
+ret = ff_mov_read_stsd_entries(c, pb, sc->stsd_count);
+if (ret < 0)
+return ret;
+
+/* Restore back the primary extradata. */
+av_free(st->codecpar->extradata);
+st->codecpar->extradata_size = sc->extradata_size[0];
+st->codecpar->extradata = av_mallocz(sc->extradata_size[0] + 
AV_INPUT_BUFFER_PADDING_SIZE);
+if (!st->codecpar->extradata)
+return AVERROR(ENOMEM);
+memcpy(st->codecpar->extradata, sc->extradata[0], sc->extradata_size[0]);
+
+return 0;
 }
 
 static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -1906,6 +1946,8 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
 sc->stsc_data[i].first = avio_rb32(pb);
 sc->stsc_data[i].count = avio_rb32(pb);
 sc->stsc_data[i].id = avio_rb32(pb);
+if (sc->stsc_data[i].id > sc->stsd_count)
+return AVERROR_INVALIDDATA;
 }
 
 sc->stsc_count = i;
@@ -1916,6 +1958,19 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, 
MOVAtom 

[libav-devel] [PATCH] mov: Implement support for multiple sample description tables

2016-06-10 Thread Vittorio Giovara
Store data from each stsd in a separate extradata buffer, keep track of
the stsc index for read and seek operations, switch buffers when the
index differs. Decoder is notified with an AV_PKT_DATA_NEW_EXTRADATA
packet side data.

Since H264 supports this notification, and can be reset midstream, enable
this feature only for multiple avcC's. All other stsd types (such as
hvc1 and hev1) need decoder-side changes, so they are left disabled for
now.

This is implemented only in non-fragmented MOVs.

Signed-off-by: Vittorio Giovara 
---
In this iteration:
- dropped the stsd_count check everywhere
- addressed the case in which ff_mov_read_stsd_entries was called by rtpdec_qt
- added a note for non-fragmented movs
- minor documentation changes
Vittorio
 libavformat/isom.h |   8 
 libavformat/mov.c  | 112 ++---
 2 files changed, 114 insertions(+), 6 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index aec623b..75aa70b 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -105,6 +105,8 @@ typedef struct MOVStreamContext {
 MOVStts *ctts_data;
 unsigned int stsc_count;
 MOVStsc *stsc_data;
+int stsc_index;
+int stsc_sample;
 unsigned int stps_count;
 unsigned *stps_data;  ///< partial sync sample for mpeg-2 open gop
 int ctts_index;
@@ -137,6 +139,12 @@ typedef struct MOVStreamContext {
 unsigned int rap_group_count;
 MOVSbgp *rap_group;
 
+/** extradata array (and size) for multiple stsd */
+uint8_t **extradata;
+int *extradata_size;
+int last_stsd_index;
+int stsd_count;
+
 int32_t *display_matrix;
 } MOVStreamContext;
 
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 125919f..30f49b6 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1771,8 +1771,7 @@ static int mov_skip_multiple_stsd(MOVContext *c, 
AVIOContext *pb,
 int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format);
 
 if (codec_tag &&
-(codec_tag == AV_RL32("avc1") ||
- codec_tag == AV_RL32("hvc1") ||
+(codec_tag == AV_RL32("hvc1") ||
  codec_tag == AV_RL32("hev1") ||
  (codec_tag != format &&
   (c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id
@@ -1857,6 +1856,19 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext 
*pb, int entries)
 return ret;
 } else if (a.size > 0)
 avio_skip(pb, a.size);
+
+if (sc->extradata) {
+int extra_size = st->codecpar->extradata_size;
+
+/* Move the current stream extradata to the stream context one. */
+sc->extradata_size[pseudo_stream_id] = extra_size;
+sc->extradata[pseudo_stream_id] = av_malloc(extra_size + 
AV_INPUT_BUFFER_PADDING_SIZE);
+if (!sc->extradata[pseudo_stream_id])
+return AVERROR(ENOMEM);
+memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, 
extra_size);
+av_freep(>codecpar->extradata);
+st->codecpar->extradata_size = 0;
+}
 }
 
 if (pb->eof_reached)
@@ -1867,13 +1879,41 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext 
*pb, int entries)
 
 static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
-int entries;
+AVStream *st;
+MOVStreamContext *sc;
+int ret;
+
+if (c->fc->nb_streams < 1)
+return 0;
+st = c->fc->streams[c->fc->nb_streams - 1];
+sc = st->priv_data;
 
 avio_r8(pb); /* version */
 avio_rb24(pb); /* flags */
-entries = avio_rb32(pb);
+sc->stsd_count = avio_rb32(pb); /* entries */
+
+/* Prepare space for hosting multiple extradata. */
+sc->extradata = av_mallocz_array(sc->stsd_count, sizeof(*sc->extradata));
+if (!sc->extradata)
+return AVERROR(ENOMEM);
+
+sc->extradata_size = av_mallocz_array(sc->stsd_count, 
sizeof(sc->extradata_size));
+if (!sc->extradata_size)
+return AVERROR(ENOMEM);
 
-return ff_mov_read_stsd_entries(c, pb, entries);
+ret = ff_mov_read_stsd_entries(c, pb, sc->stsd_count);
+if (ret < 0)
+return ret;
+
+/* Restore back the primary extradata. */
+av_free(st->codecpar->extradata);
+st->codecpar->extradata_size = sc->extradata_size[0];
+st->codecpar->extradata = av_mallocz(sc->extradata_size[0] + 
AV_INPUT_BUFFER_PADDING_SIZE);
+if (!st->codecpar->extradata)
+return AVERROR(ENOMEM);
+memcpy(st->codecpar->extradata, sc->extradata[0], sc->extradata_size[0]);
+
+return 0;
 }
 
 static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -1916,6 +1956,19 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
 return 0;
 }
 
+/* Compute the samples value for the stsc entry at the given index. */
+static inline int mov_get_stsc_samples(MOVStreamContext *sc, int index)
+{
+int chunk_count;
+
+if (index < sc->stsc_count