Opened 9 days ago

Last modified 9 days ago

#7592 new defect

FFmpeg download data twice

Reported by: atrzcinski Owned by:
Priority: normal Component: avformat
Version: unspecified Keywords: mov
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

In case of data muxed in a way, that video and audio packets for the same ptses are more than 1 sec distant (so when ff_configure_buffers_for_index changes size of AVIOContext buffers to 2 * biggest_distance_between_data_for_1_sec_pts) FFmpeg fetches the same data twice from the server. This is because in fill_buffer in aviobuf.c when we need data audio from pts x that we don't currently have in buffer, we drop the whole buffer and download new range. But afterward, we need video from pts x, which was in buffer already (before seek caused by audio), so we drop buffer again and seek to this position.

Attachments (2)

fmp4.png (57.1 KB) - added by atrzcinski 9 days ago.
data_order_in_file
log.txt (637.6 KB) - added by atrzcinski 9 days ago.
./ffmpeg -v 9 -loglevel 99 -i "http://shadow.corp.vewd.com/atrzcinski/TVSDK-38215/a.mp4"

Download all attachments as: .zip

Change History (5)

Changed 9 days ago by atrzcinski

data_order_in_file

Changed 9 days ago by atrzcinski

comment:1 Changed 9 days ago by atrzcinski

This is a solution I used to solve this problem:

diff --git a/third_party/ffmpeg/libavformat/avio.h b/third_party/ffmpeg/libavformat/avio.h
index 75912ce6bed9..c44e1c7e9c9b 100644
--- a/third_party/ffmpeg/libavformat/avio.h
+++ b/third_party/ffmpeg/libavformat/avio.h
@@ -225,6 +225,7 @@ typedef struct AVIOContext {
      */
     unsigned char *buffer;  /**< Start of the buffer. */
     int buffer_size;        /**< Maximum buffer size */
+    int time_units_in_buffer; /**< Number of time units in buffer */
     unsigned char *buf_ptr; /**< Current position in the buffer */
     unsigned char *buf_end; /**< End of the data, may be less than
                                  buffer+buffer_size if the read function returned
diff --git a/third_party/ffmpeg/libavformat/aviobuf.c b/third_party/ffmpeg/libavformat/aviobuf.c
index 5a33f82950c3..afccc61491bd 100644
--- a/third_party/ffmpeg/libavformat/aviobuf.c
+++ b/third_party/ffmpeg/libavformat/aviobuf.c
@@ -92,6 +92,7 @@ int ffio_init_context(AVIOContext *s,
     s->buffer      = buffer;
     s->orig_buffer_size =
     s->buffer_size = buffer_size;
+    s->time_units_in_buffer = 0;
     s->buf_ptr     = buffer;
     s->buf_ptr_max = buffer;
     s->opaque      = opaque;
@@ -550,9 +551,19 @@ static void fill_buffer(AVIOContext *s)
 {
     int max_buffer_size = s->max_packet_size ?
                           s->max_packet_size : IO_BUFFER_SIZE;
-    uint8_t *dst        = s->buf_end - s->buffer + max_buffer_size < s->buffer_size ?
-                          s->buf_end : s->buffer;
-    int len             = s->buffer_size - (dst - s->buffer);
+    int need_erase = !(s->buf_end - s->buffer + max_buffer_size < s->buffer_size);
+    uint8_t *dst = need_erase ? s->buffer : s->buf_end;
+    int len;
+
+    if (need_erase && s->time_units_in_buffer > 1) {
+        const int bytes_in_time_unit = (s->buf_end - s->buffer) / s->time_units_in_buffer;
+        const int offset = bytes_in_time_unit * (s->time_units_in_buffer - 1);
+        memcpy(s->buffer, s->buffer + offset, bytes_in_time_unit);
+        dst = s->buf_end = s->buffer + bytes_in_time_unit;
+        s->buf_ptr = s->buf_ptr - s->buffer < offset ? s->buffer : s->buf_ptr - offset;
+    }
+
+    len = s->buffer_size - (dst - s->buffer);
 
     /* can't fill the buffer without read_packet, just set EOF if appropriate */
     if (!s->read_packet && s->buf_ptr >= s->buf_end)
@@ -562,7 +573,7 @@ static void fill_buffer(AVIOContext *s)
     if (s->eof_reached)
         return;
 
-    if (s->update_checksum && dst == s->buffer) {
+    if (s->update_checksum && need_erase) {
         if (s->buf_end > s->checksum_ptr)
             s->checksum = s->update_checksum(s->checksum, s->checksum_ptr,
                                              s->buf_end - s->checksum_ptr);
@@ -571,7 +582,7 @@ static void fill_buffer(AVIOContext *s)
 
     /* make buffer smaller in case it ended up large after probing */
     if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size) {
-        if (dst == s->buffer && s->buf_ptr != dst) {
+        if (need_erase  && s->buf_ptr != dst) {
             int ret = ffio_set_buf_size(s, s->orig_buffer_size);
             if (ret < 0)
                 av_log(s, AV_LOG_WARNING, "Failed to decrease buffer size\n");
diff --git a/third_party/ffmpeg/libavformat/utils.c b/third_party/ffmpeg/libavformat/utils.c
index c6901174432c..3d5040025cfb 100644
--- a/third_party/ffmpeg/libavformat/utils.c
+++ b/third_party/ffmpeg/libavformat/utils.c
@@ -2137,6 +2137,7 @@ void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
         av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta);
         ffio_set_buf_size(s->pb, pos_delta);
         s->pb->short_seek_threshold = FFMAX(s->pb->short_seek_threshold, pos_delta/2);
+        s->pb->time_units_in_buffer = 2;
     }
 
     if (skip < (1<<23)) {
Last edited 9 days ago by atrzcinski (previous) (diff)

comment:2 Changed 9 days ago by atrzcinski

Code in fill_buffer in
if (need_erase ....)
might be simplified taking into account, that buffer_size is always 0 or 2, so offset and time_unit is half if buffer_size is different than 0.

comment:3 Changed 9 days ago by cehoyos

  • Keywords mov added

Looks like a duplicate of several other tickets.
If you really believe you may have fixed the issue please send your patch made with git format-patch to the development mailing list.

Note: See TracTickets for help on using tickets.