]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/smacker.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavcodec / smacker.c
index 3a4ba1a1144b1d76caf4f86be71db6bb9eafafaf..8345b7f8a0e29a1240526277c578b3a75a32fe61 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "avcodec.h"
 #include "libavutil/audioconvert.h"
+#include "mathops.h"
 
 #define ALT_BITSTREAM_READER_LE
 #include "get_bits.h"
@@ -367,7 +368,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac
     if(buf_size <= 769)
         return 0;
 
-    smk->pic.reference = 1;
+    smk->pic.reference = 3;
     smk->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
     if(avctx->reget_buffer(avctx, &smk->pic) < 0){
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
@@ -560,6 +561,10 @@ static av_cold int decode_end(AVCodecContext *avctx)
 
 static av_cold int smka_decode_init(AVCodecContext *avctx)
 {
+    if (avctx->channels < 1 || avctx->channels > 2) {
+        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
+        return AVERROR(EINVAL);
+    }
     avctx->channel_layout = (avctx->channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
     avctx->sample_fmt = avctx->bits_per_coded_sample == 8 ? AV_SAMPLE_FMT_U8 : AV_SAMPLE_FMT_S16;
     return 0;
@@ -576,13 +581,18 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
     HuffContext h[4];
     VLC vlc[4];
     int16_t *samples = data;
-    int8_t *samples8 = data;
+    uint8_t *samples8 = data;
     int val;
     int i, res;
     int unp_size;
     int bits, stereo;
     int pred[2] = {0, 0};
 
+    if (buf_size <= 4) {
+        av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
+        return AVERROR(EINVAL);
+    }
+
     unp_size = AV_RL32(buf);
 
     init_get_bits(&gb, buf + 4, (buf_size - 4) * 8);
@@ -598,6 +608,14 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
         av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n");
         return -1;
     }
+    if (stereo ^ (avctx->channels != 1)) {
+        av_log(avctx, AV_LOG_ERROR, "channels mismatch\n");
+        return AVERROR(EINVAL);
+    }
+    if (bits && avctx->sample_fmt == AV_SAMPLE_FMT_U8) {
+        av_log(avctx, AV_LOG_ERROR, "sample format mismatch\n");
+        return AVERROR(EINVAL);
+    }
 
     memset(vlc, 0, sizeof(VLC) * 4);
     memset(h, 0, sizeof(HuffContext) * 4);
@@ -639,8 +657,8 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                 else
                     res = 0;
                 val |= h[3].values[res] << 8;
-                pred[1] += (int16_t)val;
-                *samples++ = pred[1];
+                pred[1] += sign_extend(val, 16);
+                *samples++ = av_clip_int16(pred[1]);
             } else {
                 if(vlc[0].table)
                     res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
@@ -652,8 +670,8 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                 else
                     res = 0;
                 val |= h[1].values[res] << 8;
-                pred[0] += val;
-                *samples++ = pred[0];
+                pred[0] += sign_extend(val, 16);
+                *samples++ = av_clip_int16(pred[0]);
             }
         }
     } else { //8-bit data
@@ -667,15 +685,15 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                     res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
                 else
                     res = 0;
-                pred[1] += (int8_t)h[1].values[res];
-                *samples8++ = pred[1];
+                pred[1] += sign_extend(h[1].values[res], 8);
+                *samples8++ = av_clip_uint8(pred[1]);
             } else {
                 if(vlc[0].table)
                     res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
                 else
                     res = 0;
-                pred[0] += (int8_t)h[0].values[res];
-                *samples8++ = pred[0];
+                pred[0] += sign_extend(h[0].values[res], 8);
+                *samples8++ = av_clip_uint8(pred[0]);
             }
         }
     }