movenc: add fallback audio track tref support

Message ID 1446741732-12011-1-git-send-email-stebbins@jetheaddev.com
State New
Headers show

Commit Message

John Stebbins Nov. 5, 2015, 4:42 p.m.
This feature allows making associations between audio tracks
that apple players recognize.  E.g. when an ac3 track has a
tref that points to an aac track, devices that don't support
ac3 will automatically fall back to the aac track.

Apple used to *guess* these associations, but new products
(AppleTV 4) no longer guess and this association can only
be made explicitly now using the "fall" tref.
---
 libavcodec/avcodec.h     |  8 ++++++++
 libavformat/avformat.h   | 10 ++++++++++
 libavformat/internal.h   |  7 -------
 libavformat/mov.c        |  4 ++--
 libavformat/movenc.c     | 19 +++++++++++++++----
 libavformat/replaygain.c |  2 +-
 libavformat/utils.c      |  3 ++-
 7 files changed, 38 insertions(+), 15 deletions(-)

Comments

Luca Barbato Nov. 5, 2015, 5:20 p.m. | #1
On 05/11/15 17:42, John Stebbins wrote:
> This feature allows making associations between audio tracks
> that apple players recognize.  E.g. when an ac3 track has a
> tref that points to an aac track, devices that don't support
> ac3 will automatically fall back to the aac track.
> 
> Apple used to *guess* these associations, but new products
> (AppleTV 4) no longer guess and this association can only
> be made explicitly now using the "fall" tref.
> ---
>  libavcodec/avcodec.h     |  8 ++++++++
>  libavformat/avformat.h   | 10 ++++++++++
>  libavformat/internal.h   |  7 -------
>  libavformat/mov.c        |  4 ++--
>  libavformat/movenc.c     | 19 +++++++++++++++----
>  libavformat/replaygain.c |  2 +-
>  libavformat/utils.c      |  3 ++-
>  7 files changed, 38 insertions(+), 15 deletions(-)
> 

I'm not against it, Anton and Martin are you happy?

It is about 3 patches in one though:

- expose the helper function to make a new side data for streams
- add the new side data value
- use it

So might be extra nice to have 3 of them instead of one.

lu

Patch

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index e368d6b..ba4b088 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1129,6 +1129,14 @@  enum AVPacketSideDataType {
      * and FF_LAMBDA_MAX (bad).
      */
     AV_PKT_DATA_QUALITY_FACTOR,
+
+    /**
+     * This side data contains an integer value representing the stream index
+     * of a "fallback" track.  A fallback track indicates an alternate
+     * track to use when the current track can not be decoded for some reason.
+     * e.g. no decoder available for codec.
+     */
+    AV_PKT_DATA_FALLBACK_TRACK,
 };
 
 typedef struct AVPacketSideData {
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 470bbc6..18cef52 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1336,6 +1336,16 @@  const AVClass *avformat_get_class(void);
 AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);
 
 /**
+ * Allocate new information from stream.
+ *
+ * @param stream stream
+ * @param type desired side information type
+ * @param size side information size
+ * @return pointer to fresh allocated data or NULL otherwise
+ */
+uint8_t *av_stream_new_side_data(AVStream *stream,
+                                 enum AVPacketSideDataType type, int size);
+/**
  * Get side information from stream.
  *
  * @param stream stream
diff --git a/libavformat/internal.h b/libavformat/internal.h
index a65a3b7..738db04 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -407,11 +407,4 @@  static inline int ff_rename(const char *oldpath, const char *newpath)
     return 0;
 }
 
-/**
- * Add new side data to a stream. If a side data of this type already exists, it
- * is replaced.
- */
-uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
-                                 int size);
-
 #endif /* AVFORMAT_INTERNAL_H */
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 9532213..4593bbb 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -681,7 +681,7 @@  static int mov_read_dac3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         return 0;
     st = c->fc->streams[c->fc->nb_streams-1];
 
-    ast = (enum AVAudioServiceType*)ff_stream_new_side_data(st, AV_PKT_DATA_AUDIO_SERVICE_TYPE,
+    ast = (enum AVAudioServiceType*)av_stream_new_side_data(st, AV_PKT_DATA_AUDIO_SERVICE_TYPE,
                                                             sizeof(*ast));
     if (!ast)
         return AVERROR(ENOMEM);
@@ -713,7 +713,7 @@  static int mov_read_dec3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         return 0;
     st = c->fc->streams[c->fc->nb_streams-1];
 
-    ast = (enum AVAudioServiceType*)ff_stream_new_side_data(st, AV_PKT_DATA_AUDIO_SERVICE_TYPE,
+    ast = (enum AVAudioServiceType*)av_stream_new_side_data(st, AV_PKT_DATA_AUDIO_SERVICE_TYPE,
                                                             sizeof(*ast));
     if (!ast)
         return AVERROR(ENOMEM);
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 572e781..594d464 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -2285,10 +2285,21 @@  static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
             mov->tracks[i].tref_id  = mov->tracks[mov->chapter_track].track_id;
         }
     for (i = 0; i < mov->nb_streams; i++) {
-        if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) {
-            mov->tracks[i].tref_tag = MKTAG('h','i','n','t');
-            mov->tracks[i].tref_id =
-                mov->tracks[mov->tracks[i].src_track].track_id;
+        MOVTrack *track = &mov->tracks[i];
+        if (track->tag == MKTAG('r','t','p',' ')) {
+            track->tref_tag = MKTAG('h','i','n','t');
+            track->tref_id = mov->tracks[track->src_track].track_id;
+        } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
+            int * fallback, size;
+            fallback = (int*)av_stream_get_side_data(track->st,
+                                                     AV_PKT_DATA_FALLBACK_TRACK,
+                                                     &size);
+            if (fallback != NULL && size == sizeof(int)) {
+                if (*fallback >= 0 && *fallback < mov->nb_streams) {
+                    track->tref_tag = MKTAG('f','a','l','l');
+                    track->tref_id = mov->tracks[*fallback].track_id;
+                }
+            }
         }
     }
 
diff --git a/libavformat/replaygain.c b/libavformat/replaygain.c
index 98e7aad..3188b15 100644
--- a/libavformat/replaygain.c
+++ b/libavformat/replaygain.c
@@ -75,7 +75,7 @@  int ff_replaygain_export_raw(AVStream *st, int32_t tg, uint32_t tp,
     if (tg == INT32_MIN && ag == INT32_MIN)
         return 0;
 
-    replaygain = (AVReplayGain*)ff_stream_new_side_data(st, AV_PKT_DATA_REPLAYGAIN,
+    replaygain = (AVReplayGain*)av_stream_new_side_data(st, AV_PKT_DATA_REPLAYGAIN,
                                                         sizeof(*replaygain));
     if (!replaygain)
         return AVERROR(ENOMEM);
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 42f60d5..52c42fa 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3120,7 +3120,7 @@  uint8_t *av_stream_get_side_data(AVStream *st, enum AVPacketSideDataType type,
     return NULL;
 }
 
-uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
+uint8_t *av_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
                                  int size)
 {
     AVPacketSideData *sd, *tmp;
@@ -3156,3 +3156,4 @@  uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
     sd->size = size;
     return data;
 }
+