]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/g2meet.c
Merge commit '7520d9779c6d30b385df5a0a42da508238076192'
[ffmpeg] / libavcodec / g2meet.c
index d0a4302fd744ebed9b85e053d251b9c6828315f7..09ed7ce7c41ee0073eb485c4d44f0077c6b7e177 100644 (file)
@@ -2,20 +2,20 @@
  * Go2Webinar decoder
  * Copyright (c) 2012 Konstantin Shishkov
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -440,7 +440,7 @@ static int g2m_init_buffers(G2MContext *c)
 {
     int aligned_height;
 
-    if (!c->framebuf || c->old_width < c->width || c->height < c->height) {
+    if (!c->framebuf || c->old_width < c->width || c->old_height < c->height) {
         c->framebuf_stride = FFALIGN(c->width * 3, 16);
         aligned_height     = FFALIGN(c->height,    16);
         av_free(c->framebuf);
@@ -455,6 +455,8 @@ static int g2m_init_buffers(G2MContext *c)
         aligned_height = FFALIGN(c->tile_height,    16);
         av_free(c->synth_tile);
         av_free(c->jpeg_tile);
+        av_free(c->kempf_buf);
+        av_free(c->kempf_flags);
         c->synth_tile  = av_mallocz(c->tile_stride      * aligned_height);
         c->jpeg_tile   = av_mallocz(c->tile_stride      * aligned_height);
         c->kempf_buf   = av_mallocz((c->tile_width + 1) * aligned_height
@@ -468,16 +470,68 @@ static int g2m_init_buffers(G2MContext *c)
     return 0;
 }
 
-static int g2m_load_cursor(G2MContext *c, GetByteContext *gb)
+static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
+                           GetByteContext *gb)
 {
     int i, j, k;
     uint8_t *dst;
     uint32_t bits;
+    uint32_t cur_size, cursor_w, cursor_h, cursor_stride;
+    uint32_t cursor_hot_x, cursor_hot_y;
+    int cursor_fmt;
+    uint8_t *tmp;
 
-    c->cursor_stride = c->cursor_w * 4;
-    c->cursor        = av_realloc(c->cursor, c->cursor_stride * c->cursor_h);
-    if (!c->cursor)
+    cur_size      = bytestream2_get_be32(gb);
+    cursor_w      = bytestream2_get_byte(gb);
+    cursor_h      = bytestream2_get_byte(gb);
+    cursor_hot_x  = bytestream2_get_byte(gb);
+    cursor_hot_y  = bytestream2_get_byte(gb);
+    cursor_fmt    = bytestream2_get_byte(gb);
+
+    cursor_stride = cursor_w * 4;
+
+    if (cursor_w < 1 || cursor_w > 256 ||
+        cursor_h < 1 || cursor_h > 256) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid cursor dimensions %dx%d\n",
+               cursor_w, cursor_h);
+        return AVERROR_INVALIDDATA;
+    }
+    if (cursor_hot_x > cursor_w || cursor_hot_y > cursor_h) {
+        av_log(avctx, AV_LOG_WARNING, "Invalid hotspot position %d,%d\n",
+               cursor_hot_x, cursor_hot_y);
+        cursor_hot_x = FFMIN(cursor_hot_x, cursor_w - 1);
+        cursor_hot_y = FFMIN(cursor_hot_y, cursor_h - 1);
+    }
+    if (cur_size - 9 > bytestream2_get_bytes_left(gb) ||
+        c->cursor_w * c->cursor_h / 4 > cur_size) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid cursor data size %d/%d\n",
+               cur_size, bytestream2_get_bytes_left(gb));
+        return AVERROR_INVALIDDATA;
+    }
+    if (cursor_fmt != 1 && cursor_fmt != 32) {
+        avpriv_report_missing_feature(avctx, "Cursor format %d",
+                                      cursor_fmt);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    if (cursor_fmt == 1 && cursor_w % 32) {
+        avpriv_report_missing_feature(avctx, "odd monochrome cursor width %d", cursor_w);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    tmp = av_realloc(c->cursor, cursor_stride * cursor_h);
+    if (!tmp) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot allocate cursor buffer\n");
         return AVERROR(ENOMEM);
+    }
+
+    c->cursor        = tmp;
+    c->cursor_w      = cursor_w;
+    c->cursor_h      = cursor_h;
+    c->cursor_hot_x  = cursor_hot_x;
+    c->cursor_hot_y  = cursor_hot_y;
+    c->cursor_fmt    = cursor_fmt;
+    c->cursor_stride = cursor_stride;
 
     dst = c->cursor;
     switch (c->cursor_fmt) {
@@ -597,7 +651,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
     GetByteContext bc, tbc;
     int magic;
     int got_header = 0;
-    uint32_t chunk_size, cur_size;
+    uint32_t chunk_size;
     int chunk_type;
     int i;
     int ret;
@@ -734,19 +788,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
             }
             bytestream2_init(&tbc, buf + bytestream2_tell(&bc),
                              chunk_size - 4);
-            cur_size        = bytestream2_get_be32(&tbc);
-            c->cursor_w     = bytestream2_get_byte(&tbc);
-            c->cursor_h     = bytestream2_get_byte(&tbc);
-            c->cursor_hot_x = bytestream2_get_byte(&tbc);
-            c->cursor_hot_y = bytestream2_get_byte(&tbc);
-            c->cursor_fmt   = bytestream2_get_byte(&tbc);
-            if (cur_size >= chunk_size ||
-                c->cursor_w * c->cursor_h / 4 > cur_size) {
-                av_log(avctx, AV_LOG_ERROR, "Invalid cursor data size %d\n",
-                       chunk_size);
-                break;
-            }
-            g2m_load_cursor(c, &tbc);
+            g2m_load_cursor(avctx, c, &tbc);
             bytestream2_skip(&bc, chunk_size);
             break;
         case CHUNK_CC:
@@ -762,7 +804,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
     if (got_header)
         c->got_header = 1;
 
-    if (c->width && c->height) {
+    if (c->width && c->height && c->framebuf) {
         if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) {
             av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
             return ret;