]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/screenpresso.c
network: Use ff_neterrno instead of AVERROR(errno) for poll errors
[ffmpeg] / libavcodec / screenpresso.c
index d25d0ebb9d067775d4a6cf8f0da742abcd31ea0e..eae0ae72e5e86de8fa40b10216dc39059cbd5487 100644 (file)
@@ -30,7 +30,7 @@
  * rebuilt frame (not the reference), and since there is no coordinate system
  * they contain exactly as many pixel as the keyframe.
  *
- * Supports: BGR24
+ * Supports: BGRA, BGR24, RGB555
  */
 
 #include <stdint.h>
@@ -39,6 +39,7 @@
 
 #include "libavutil/imgutils.h"
 #include "libavutil/internal.h"
+#include "libavutil/mem.h"
 
 #include "avcodec.h"
 #include "internal.h"
@@ -46,7 +47,7 @@
 typedef struct ScreenpressoContext {
     AVFrame *current;
 
-    /* zlib interation */
+    /* zlib interaction */
     uint8_t *inflated_buf;
     uLongf inflated_size;
 } ScreenpressoContext;
@@ -78,7 +79,11 @@ static av_cold int screenpresso_init(AVCodecContext *avctx)
     if (!ctx->current)
         return AVERROR(ENOMEM);
 
-    avctx->pix_fmt = AV_PIX_FMT_BGR24;
+    /* Allocate maximum size possible, a full RGBA frame */
+    ctx->inflated_size = avctx->width * avctx->height * 4;
+    ctx->inflated_buf  = av_malloc(ctx->inflated_size);
+    if (!ctx->inflated_buf)
+        return AVERROR(ENOMEM);
 
     return 0;
 }
@@ -100,7 +105,8 @@ static int screenpresso_decode_frame(AVCodecContext *avctx, void *data,
 {
     ScreenpressoContext *ctx = avctx->priv_data;
     AVFrame *frame = data;
-    int keyframe;
+    uLongf length = ctx->inflated_size;
+    int keyframe, component_size, src_linesize;
     int ret;
 
     /* Size check */
@@ -109,50 +115,55 @@ static int screenpresso_decode_frame(AVCodecContext *avctx, void *data,
         return AVERROR_INVALIDDATA;
     }
 
-    /* Basic sanity check, but not really harmful */
-    if ((avpkt->data[0] != 0x73 && avpkt->data[0] != 0x72) ||
-        avpkt->data[1] != 8) { // bpp probably
-        av_log(avctx, AV_LOG_WARNING, "Unknown header 0x%02X%02X\n",
-               avpkt->data[0], avpkt->data[1]);
-    }
-    keyframe = (avpkt->data[0] == 0x73);
-
-    /* Resize deflate buffer and frame on resolution change */
-    if (ctx->inflated_size != avctx->width * avctx->height * 3) {
-        av_frame_unref(ctx->current);
-        ret = ff_get_buffer(avctx, ctx->current, AV_GET_BUFFER_FLAG_REF);
-        if (ret < 0)
-            return ret;
-
-        /* If malloc fails, reset len to avoid preserving an invalid value */
-        ctx->inflated_size = avctx->width * avctx->height * 3;
-        ret = av_reallocp(&ctx->inflated_buf, ctx->inflated_size);
-        if (ret < 0) {
-            ctx->inflated_size = 0;
-            return ret;
-        }
+    /* Compression level (4 bits) and keyframe information (1 bit) */
+    av_log(avctx, AV_LOG_DEBUG, "Compression level %d\n", avpkt->data[0] >> 4);
+    keyframe = avpkt->data[0] & 1;
+
+    /* Pixel size */
+    component_size = ((avpkt->data[1] >> 2) & 0x03) + 1;
+    switch (component_size) {
+    case 2:
+        avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
+        break;
+    case 3:
+        avctx->pix_fmt = AV_PIX_FMT_BGR24;
+        break;
+    case 4:
+        avctx->pix_fmt = AV_PIX_FMT_BGRA;
+        break;
+    default:
+        av_log(avctx, AV_LOG_ERROR, "Invalid bits per pixel value (%d)\n",
+               component_size);
+        return AVERROR_INVALIDDATA;
     }
 
     /* Inflate the frame after the 2 byte header */
-    ret = uncompress(ctx->inflated_buf, &ctx->inflated_size,
+    ret = uncompress(ctx->inflated_buf, &length,
                      avpkt->data + 2, avpkt->size - 2);
     if (ret) {
         av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret);
         return AVERROR_UNKNOWN;
     }
 
+    ret = ff_reget_buffer(avctx, ctx->current);
+    if (ret < 0)
+        return ret;
+
+    /* Codec has aligned strides */
+    src_linesize = FFALIGN(avctx->width * component_size, 4);
+
     /* When a keyframe is found, copy it (flipped) */
     if (keyframe)
         av_image_copy_plane(ctx->current->data[0] +
                             ctx->current->linesize[0] * (avctx->height - 1),
                             -1 * ctx->current->linesize[0],
-                            ctx->inflated_buf, avctx->width * 3,
-                            avctx->width * 3, avctx->height);
+                            ctx->inflated_buf, src_linesize,
+                            avctx->width * component_size, avctx->height);
     /* Otherwise sum the delta on top of the current frame */
     else
         sum_delta_flipped(ctx->current->data[0], ctx->current->linesize[0],
-                          ctx->inflated_buf, avctx->width * 3,
-                          avctx->width * 3, avctx->height);
+                          ctx->inflated_buf, src_linesize,
+                          avctx->width * component_size, avctx->height);
 
     /* Frame is ready to be output */
     ret = av_frame_ref(frame, ctx->current);