]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/vmdav.c
avidec: Fix infinite loop caused by rounding of timestamps in non interleaved avis.
[ffmpeg] / libavcodec / vmdav.c
index 63ac33db593a6a292add8799ee8f8209b905f059..ec7c967f743b0fd5a69024d95bd938998dc50a9c 100644 (file)
@@ -264,7 +264,8 @@ static void vmd_decode(VmdVideoContext *s)
             r = *p++ * 4;
             g = *p++ * 4;
             b = *p++ * 4;
-            palette32[i] = (r << 16) | (g << 8) | (b);
+            palette32[i] = 0xFF << 24 | r << 16 | g << 8 | b;
+            palette32[i] |= palette32[i] >> 6 & 0x30303;
         }
     }
     if (p < p_end) {
@@ -421,7 +422,7 @@ static int vmdvideo_decode_frame(AVCodecContext *avctx,
     if (buf_size < 16)
         return buf_size;
 
-    s->frame.reference = 1;
+    s->frame.reference = 3;
     if (avctx->get_buffer(avctx, &s->frame)) {
         av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
         return -1;
@@ -465,6 +466,7 @@ static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
 #define BLOCK_TYPE_SILENCE  3
 
 typedef struct VmdAudioContext {
+    AVFrame frame;
     int out_bps;
     int chunk_size;
 } VmdAudioContext;
@@ -506,6 +508,9 @@ static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
 
     s->chunk_size = avctx->block_align + avctx->channels * (s->out_bps == 2);
 
+    avcodec_get_frame_defaults(&s->frame);
+    avctx->coded_frame = &s->frame;
+
     av_log(avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, "
            "block align = %d, sample rate = %d\n",
            avctx->channels, avctx->bits_per_coded_sample, avctx->block_align,
@@ -543,22 +548,21 @@ static void decode_audio_s16(int16_t *out, const uint8_t *buf, int buf_size,
     }
 }
 
-static int vmdaudio_decode_frame(AVCodecContext *avctx,
-                                 void *data, int *data_size,
-                                 AVPacket *avpkt)
+static int vmdaudio_decode_frame(AVCodecContext *avctx, void *data,
+                                 int *got_frame_ptr, AVPacket *avpkt)
 {
     const uint8_t *buf = avpkt->data;
     const uint8_t *buf_end;
     int buf_size = avpkt->size;
     VmdAudioContext *s = avctx->priv_data;
     int block_type, silent_chunks, audio_chunks;
-    int nb_samples, out_size;
-    uint8_t *output_samples_u8  = data;
-    int16_t *output_samples_s16 = data;
+    int ret;
+    uint8_t *output_samples_u8;
+    int16_t *output_samples_s16;
 
     if (buf_size < 16) {
         av_log(avctx, AV_LOG_WARNING, "skipping small junk packet\n");
-        *data_size = 0;
+        *got_frame_ptr = 0;
         return buf_size;
     }
 
@@ -589,10 +593,15 @@ static int vmdaudio_decode_frame(AVCodecContext *avctx,
 
     /* ensure output buffer is large enough */
     audio_chunks = buf_size / s->chunk_size;
-    nb_samples   = ((silent_chunks + audio_chunks) * avctx->block_align) / avctx->channels;
-    out_size     = nb_samples * avctx->channels * s->out_bps;
-    if (*data_size < out_size)
-        return -1;
+
+    /* get output buffer */
+    s->frame.nb_samples = ((silent_chunks + audio_chunks) * avctx->block_align) / avctx->channels;
+    if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        return ret;
+    }
+    output_samples_u8  = s->frame.data[0];
+    output_samples_s16 = (int16_t *)s->frame.data[0];
 
     /* decode silent chunks */
     if (silent_chunks > 0) {
@@ -622,7 +631,9 @@ static int vmdaudio_decode_frame(AVCodecContext *avctx,
         }
     }
 
-    *data_size = out_size;
+    *got_frame_ptr   = 1;
+    *(AVFrame *)data = s->frame;
+
     return avpkt->size;
 }
 
@@ -650,5 +661,6 @@ AVCodec ff_vmdaudio_decoder = {
     .priv_data_size = sizeof(VmdAudioContext),
     .init           = vmdaudio_decode_init,
     .decode         = vmdaudio_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
     .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
 };