]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/webm_chunk.c
avformat/spdifenc: fix handling of large TrueHD frames
[ffmpeg] / libavformat / webm_chunk.c
index 7ceb276fc436bede080f2d3dda6ad1415220b931..4e2ce21a797cc07282a5bf53ba3661ddc111ebd1 100644 (file)
@@ -52,8 +52,8 @@ typedef struct WebMChunkContext {
     int chunk_index;
     char *http_method;
     uint64_t duration_written;
-    int prev_pts;
-    AVOutputFormat *oformat;
+    int64_t prev_pts;
+    ff_const59 AVOutputFormat *oformat;
     AVFormatContext *avf;
 } WebMChunkContext;
 
@@ -84,7 +84,7 @@ static int chunk_mux_init(AVFormatContext *s)
     return 0;
 }
 
-static int get_chunk_filename(AVFormatContext *s, int is_header, char *filename)
+static int get_chunk_filename(AVFormatContext *s, int is_header, char filename[MAX_FILENAME_SIZE])
 {
     WebMChunkContext *wc = s->priv_data;
     AVFormatContext *oc = wc->avf;
@@ -92,11 +92,16 @@ static int get_chunk_filename(AVFormatContext *s, int is_header, char *filename)
         return AVERROR(EINVAL);
     }
     if (is_header) {
+        int len;
         if (!wc->header_filename) {
             av_log(oc, AV_LOG_ERROR, "No header filename provided\n");
             return AVERROR(EINVAL);
         }
-        av_strlcpy(filename, wc->header_filename, strlen(wc->header_filename) + 1);
+        len = av_strlcpy(filename, wc->header_filename, MAX_FILENAME_SIZE);
+        if (len >= MAX_FILENAME_SIZE) {
+            av_log(oc, AV_LOG_ERROR, "Header filename too long\n");
+            return AVERROR(EINVAL);
+        }
     } else {
         if (av_get_frame_filename(filename, MAX_FILENAME_SIZE,
                                   s->url, wc->chunk_index - 1) < 0) {
@@ -124,6 +129,7 @@ static int webm_chunk_write_header(AVFormatContext *s)
     wc->oformat = av_guess_format("webm", s->url, "video/webm");
     if (!wc->oformat)
         return AVERROR_MUXER_NOT_FOUND;
+    wc->prev_pts = AV_NOPTS_VALUE;
 
     ret = chunk_mux_init(s);
     if (ret < 0)
@@ -168,7 +174,7 @@ static int chunk_start(AVFormatContext *s)
     return 0;
 }
 
-static int chunk_end(AVFormatContext *s)
+static int chunk_end(AVFormatContext *s, int flush)
 {
     WebMChunkContext *wc = s->priv_data;
     AVFormatContext *oc = wc->avf;
@@ -179,11 +185,14 @@ static int chunk_end(AVFormatContext *s)
     char filename[MAX_FILENAME_SIZE];
     AVDictionary *options = NULL;
 
-    if (wc->chunk_start_index == wc->chunk_index)
+    if (!oc->pb)
         return 0;
-    // Flush the cluster in WebM muxer.
-    oc->oformat->write_packet(oc, NULL);
+
+    if (flush)
+        // Flush the cluster in WebM muxer.
+        oc->oformat->write_packet(oc, NULL);
     buffer_size = avio_close_dyn_buf(oc->pb, &buffer);
+    oc->pb = NULL;
     ret = get_chunk_filename(s, 0, filename);
     if (ret < 0)
         goto fail;
@@ -194,7 +203,6 @@ static int chunk_end(AVFormatContext *s)
         goto fail;
     avio_write(pb, buffer, buffer_size);
     ff_format_io_close(s, &pb);
-    oc->pb = NULL;
 fail:
     av_dict_free(&options);
     av_free(buffer);
@@ -209,34 +217,27 @@ static int webm_chunk_write_packet(AVFormatContext *s, AVPacket *pkt)
     int ret;
 
     if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
-        wc->duration_written += av_rescale_q(pkt->pts - wc->prev_pts,
-                                             st->time_base,
-                                             (AVRational) {1, 1000});
+        if (wc->prev_pts != AV_NOPTS_VALUE)
+            wc->duration_written += av_rescale_q(pkt->pts - wc->prev_pts,
+                                                 st->time_base,
+                                                 (AVRational) {1, 1000});
         wc->prev_pts = pkt->pts;
     }
 
     // For video, a new chunk is started only on key frames. For audio, a new
-    // chunk is started based on chunk_duration.
-    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+    // chunk is started based on chunk_duration. Also, a new chunk is started
+    // unconditionally if there is no currently open chunk.
+    if (!oc->pb || (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
          (pkt->flags & AV_PKT_FLAG_KEY)) ||
         (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
-         (pkt->pts == 0 || wc->duration_written >= wc->chunk_duration))) {
+         wc->duration_written >= wc->chunk_duration)) {
         wc->duration_written = 0;
-        if ((ret = chunk_end(s)) < 0 || (ret = chunk_start(s)) < 0) {
-            goto fail;
+        if ((ret = chunk_end(s, 1)) < 0 || (ret = chunk_start(s)) < 0) {
+            return ret;
         }
     }
 
     ret = oc->oformat->write_packet(oc, pkt);
-    if (ret < 0)
-        goto fail;
-
-fail:
-    if (ret < 0) {
-        oc->streams = NULL;
-        oc->nb_streams = 0;
-        avformat_free_context(oc);
-    }
 
     return ret;
 }
@@ -245,12 +246,20 @@ static int webm_chunk_write_trailer(AVFormatContext *s)
 {
     WebMChunkContext *wc = s->priv_data;
     AVFormatContext *oc = wc->avf;
+    int ret;
+
+    if (!oc->pb) {
+        ret = chunk_start(s);
+        if (ret < 0)
+            goto fail;
+    }
     oc->oformat->write_trailer(oc);
-    chunk_end(s);
+    ret = chunk_end(s, 0);
+fail:
     oc->streams = NULL;
     oc->nb_streams = 0;
     avformat_free_context(oc);
-    return 0;
+    return ret;
 }
 
 #define OFFSET(x) offsetof(WebMChunkContext, x)