movenc: Use the actual converted sample for RTP hinting

Message ID 1323460447-9833-1-git-send-email-martin@martin.st
State Committed
Commit e2484fb644b8dc0a0704e4155100c897e6e9739c
Headers show

Commit Message

Martin Storsjö Dec. 9, 2011, 7:54 p.m.
If an annex b bitstream is muxed into mov, the actual written
sample is reformatted to mp4 syntax before writing.

Currently, the RTP hints that copy data from the normal video
track, where the payload data might be offset compared to the
original sample that the RTP hinting used (when 3 byte
annex b startcodes have been converted into 4 byte mp4 format
startcodes).
---
 libavformat/movenc.c     |   13 +++++++++++--
 libavformat/movenc.h     |    3 ++-
 libavformat/movenchint.c |   17 +++++++++++------
 3 files changed, 24 insertions(+), 9 deletions(-)

Comments

Luca Barbato Dec. 9, 2011, 9:24 p.m. | #1
On 09/12/11 20:54, Martin Storsjö wrote:
> If an annex b bitstream is muxed into mov, the actual written
> sample is reformatted to mp4 syntax before writing.
>
> Currently, the RTP hints that copy data from the normal video
> track, where the payload data might be offset compared to the
> original sample that the RTP hinting used (when 3 byte
> annex b startcodes have been converted into 4 byte mp4 format
> startcodes).

Not sure if this is the best solution, couldn't we just force a defined 
bitstream for all the h264 consumers and document that?

lu
Martin Storsjö Dec. 9, 2011, 10:01 p.m. | #2
On Fri, 9 Dec 2011, Luca Barbato wrote:

> On 09/12/11 20:54, Martin Storsjö wrote:
>> If an annex b bitstream is muxed into mov, the actual written
>> sample is reformatted to mp4 syntax before writing.
>>
>> Currently, the RTP hints that copy data from the normal video
>> track, where the payload data might be offset compared to the
>> original sample that the RTP hinting used (when 3 byte
>> annex b startcodes have been converted into 4 byte mp4 format
>> startcodes).
>
> Not sure if this is the best solution, couldn't we just force a defined 
> bitstream for all the h264 consumers and document that?

That'd be ideal, yes, but this is the defacto setup at the moment - the 
libx264 encoder outputs annex b, and the mov muxer only converts it to mp4 
while writing it, so for the mov muxer + rtp hinting, this is the default 
use case.

// Martin
Luca Barbato Dec. 9, 2011, 10:03 p.m. | #3
On 09/12/11 23:01, Martin Storsjö wrote:
> That'd be ideal, yes, but this is the defacto setup at the moment - the
> libx264 encoder outputs annex b, and the mov muxer only converts it to
> mp4 while writing it, so for the mov muxer + rtp hinting, this is the
> default use case.

Patch ok.

Patch

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index a741c4b..0f051d3 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -1997,6 +1997,7 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
     AVCodecContext *enc = trk->enc;
     unsigned int samplesInChunk = 0;
     int size= pkt->size;
+    uint8_t *reformatted_data = NULL;
 
     if (!s->pb->seekable) return 0; /* Can't handle that */
     if (!size) return 0; /* Discard 0 sized packets */
@@ -2033,7 +2034,13 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
     if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) {
         /* from x264 or from bytestream h264 */
         /* nal reformating needed */
-        size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
+        if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) {
+            ff_avc_parse_nal_units_buf(pkt->data, &reformatted_data,
+                                       &size);
+            avio_write(pb, reformatted_data, size);
+        } else {
+            size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
+        }
     } else {
         avio_write(pb, pkt->data, size);
     }
@@ -2088,7 +2095,9 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
     avio_flush(pb);
 
     if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams)
-        ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry);
+        ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
+                                 reformatted_data, size);
+    av_free(reformatted_data);
     return 0;
 }
 
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index bddae45..9b14f24 100644
--- a/libavformat/movenc.h
+++ b/libavformat/movenc.h
@@ -120,7 +120,8 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
 
 int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index);
 int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
-                             int track_index, int sample);
+                             int track_index, int sample,
+                             uint8_t *sample_data, int sample_size);
 void ff_mov_close_hinting(MOVTrack *track);
 
 #endif /* AVFORMAT_MOVENC_H */
diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c
index 683d58b..9f5e621 100644
--- a/libavformat/movenchint.c
+++ b/libavformat/movenchint.c
@@ -95,11 +95,12 @@  static void sample_queue_free(HintSampleQueue *queue)
  * not copied. sample_queue_retain should be called before pkt->data
  * is reused/freed.
  */
-static void sample_queue_push(HintSampleQueue *queue, AVPacket *pkt, int sample)
+static void sample_queue_push(HintSampleQueue *queue, uint8_t *data, int size,
+                              int sample)
 {
     /* No need to keep track of smaller samples, since describing them
      * with immediates is more efficient. */
-    if (pkt->size <= 14)
+    if (size <= 14)
         return;
     if (!queue->samples || queue->len >= queue->size) {
         HintSample* samples;
@@ -109,8 +110,8 @@  static void sample_queue_push(HintSampleQueue *queue, AVPacket *pkt, int sample)
             return;
         queue->samples = samples;
     }
-    queue->samples[queue->len].data = pkt->data;
-    queue->samples[queue->len].size = pkt->size;
+    queue->samples[queue->len].data = data;
+    queue->samples[queue->len].size = size;
     queue->samples[queue->len].sample_number = sample;
     queue->samples[queue->len].offset = 0;
     queue->samples[queue->len].own_data = 0;
@@ -386,7 +387,8 @@  static int write_hint_packets(AVIOContext *out, const uint8_t *data,
 }
 
 int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
-                             int track_index, int sample)
+                             int track_index, int sample,
+                             uint8_t *sample_data, int sample_size)
 {
     MOVMuxContext *mov = s->priv_data;
     MOVTrack *trk = &mov->tracks[track_index];
@@ -402,7 +404,10 @@  int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
     if (!rtp_ctx->pb)
         return AVERROR(ENOMEM);
 
-    sample_queue_push(&trk->sample_queue, pkt, sample);
+    if (sample_data)
+        sample_queue_push(&trk->sample_queue, sample_data, sample_size, sample);
+    else
+        sample_queue_push(&trk->sample_queue, pkt->data, pkt->size, sample);
 
     /* Feed the packet to the RTP muxer */
     ff_write_chained(rtp_ctx, 0, pkt, s);