⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cinepak.c

📁 ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦
💻 C
📖 第 1 页 / 共 2 页
字号:
                    s->frame.data[0][iy[3] + 1] = codebook->y3;
                    if (!s->palette_video) {
                        s->frame.data[1][iu[1]] = codebook->u;
                        s->frame.data[2][iv[1]] = codebook->v;
                    }

                    codebook = &strip->v4_codebook[*data++];
                    s->frame.data[0][iy[2] + 2] = codebook->y0;
                    s->frame.data[0][iy[2] + 3] = codebook->y1;
                    s->frame.data[0][iy[3] + 2] = codebook->y2;
                    s->frame.data[0][iy[3] + 3] = codebook->y3;
                    if (!s->palette_video) {
                        s->frame.data[1][iu[1] + 1] = codebook->u;
                        s->frame.data[2][iv[1] + 1] = codebook->v;
                    }

                }
            }

            iy[0] += 4;  iy[1] += 4;
            iy[2] += 4;  iy[3] += 4;
            iu[0] += 2;  iu[1] += 2;
            iv[0] += 2;  iv[1] += 2;
        }
    }

    return 0;
}

static int cinepak_decode_strip (CinepakContext *s,
                                 cvid_strip_t *strip, uint8_t *data, int size)
{
    uint8_t *eod = (data + size);
    int      chunk_id, chunk_size;

    /* coordinate sanity checks */
    if (strip->x1 >= s->width  || strip->x2 > s->width  ||
        strip->y1 >= s->height || strip->y2 > s->height ||
        strip->x1 >= strip->x2 || strip->y1 >= strip->y2)
        return -1;

    while ((data + 4) <= eod) {
        chunk_id   = AV_RB16 (&data[0]);
        chunk_size = AV_RB16 (&data[2]) - 4;
        if(chunk_size < 0)
            return -1;

        data      += 4;
        chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size;

        switch (chunk_id) {

        case 0x2000:
        case 0x2100:
        case 0x2400:
        case 0x2500:
            cinepak_decode_codebook (strip->v4_codebook, chunk_id,
                chunk_size, data);
            break;

        case 0x2200:
        case 0x2300:
        case 0x2600:
        case 0x2700:
            cinepak_decode_codebook (strip->v1_codebook, chunk_id,
                chunk_size, data);
            break;

        case 0x3000:
        case 0x3100:
        case 0x3200:
            return cinepak_decode_vectors (s, strip, chunk_id,
                chunk_size, data);
        }

        data += chunk_size;
    }

    return -1;
}

static int cinepak_decode (CinepakContext *s)
{
    uint8_t      *eod = (s->data + s->size);
    int           i, result, strip_size, frame_flags, num_strips;
    int           y0 = 0;
    int           encoded_buf_size;

    if (s->size < 10)
        return -1;

    frame_flags = s->data[0];
    num_strips  = AV_RB16 (&s->data[8]);
    encoded_buf_size = ((s->data[1] << 16) | AV_RB16 (&s->data[2]));

    /* if this is the first frame, check for deviant Sega FILM data */
    if (s->sega_film_skip_bytes == -1) {
        if (encoded_buf_size != s->size) {
            /* If the encoded frame size differs from the frame size as indicated
             * by the container file, this data likely comes from a Sega FILM/CPK file.
             * If the frame header is followed by the bytes FE 00 00 06 00 00 then
             * this is probably one of the two known files that have 6 extra bytes
             * after the frame header. Else, assume 2 extra bytes. */
            if ((s->data[10] == 0xFE) &&
                (s->data[11] == 0x00) &&
                (s->data[12] == 0x00) &&
                (s->data[13] == 0x06) &&
                (s->data[14] == 0x00) &&
                (s->data[15] == 0x00))
                s->sega_film_skip_bytes = 6;
            else
                s->sega_film_skip_bytes = 2;
        } else
            s->sega_film_skip_bytes = 0;
    }

    s->data += 10 + s->sega_film_skip_bytes;

    if (num_strips > MAX_STRIPS)
        num_strips = MAX_STRIPS;

    for (i=0; i < num_strips; i++) {
        if ((s->data + 12) > eod)
            return -1;

        s->strips[i].id = AV_RB16 (s->data);
        s->strips[i].y1 = y0;
        s->strips[i].x1 = 0;
        s->strips[i].y2 = y0 + AV_RB16 (&s->data[8]);
        s->strips[i].x2 = s->avctx->width;

        strip_size = AV_RB16 (&s->data[2]) - 12;
        s->data   += 12;
        strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size;

        if ((i > 0) && !(frame_flags & 0x01)) {
            memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook,
                sizeof(s->strips[i].v4_codebook));
            memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook,
                sizeof(s->strips[i].v1_codebook));
        }

        result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size);

        if (result != 0)
            return result;

        s->data += strip_size;
        y0    = s->strips[i].y2;
    }
    return 0;
}

static int cinepak_decode_init(AVCodecContext *avctx)
{
    CinepakContext *s = avctx->priv_data;

    s->avctx = avctx;
    s->width = (avctx->width + 3) & ~3;
    s->height = (avctx->height + 3) & ~3;
    s->sega_film_skip_bytes = -1;  /* uninitialized state */

    // check for paletted data
    if ((avctx->palctrl == NULL) || (avctx->bits_per_sample == 40)) {
        s->palette_video = 0;
        avctx->pix_fmt = PIX_FMT_YUV420P;
    } else {
        s->palette_video = 1;
        avctx->pix_fmt = PIX_FMT_PAL8;
    }

    dsputil_init(&s->dsp, avctx);

    s->frame.data[0] = NULL;

    return 0;
}

static int cinepak_decode_frame(AVCodecContext *avctx,
                                void *data, int *data_size,
                                uint8_t *buf, int buf_size)
{
    CinepakContext *s = avctx->priv_data;

    s->data = buf;
    s->size = buf_size;

    s->frame.reference = 1;
    s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
                            FF_BUFFER_HINTS_REUSABLE;
    if (avctx->reget_buffer(avctx, &s->frame)) {
        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
        return -1;
    }

    cinepak_decode(s);

    if (s->palette_video) {
        memcpy (s->frame.data[1], avctx->palctrl->palette, AVPALETTE_SIZE);
        if (avctx->palctrl->palette_changed) {
            s->frame.palette_has_changed = 1;
            avctx->palctrl->palette_changed = 0;
        } else
            s->frame.palette_has_changed = 0;
    }

    *data_size = sizeof(AVFrame);
    *(AVFrame*)data = s->frame;

    /* report that the buffer was completely consumed */
    return buf_size;
}

static int cinepak_decode_end(AVCodecContext *avctx)
{
    CinepakContext *s = avctx->priv_data;

    if (s->frame.data[0])
        avctx->release_buffer(avctx, &s->frame);

    return 0;
}

AVCodec cinepak_decoder = {
    "cinepak",
    CODEC_TYPE_VIDEO,
    CODEC_ID_CINEPAK,
    sizeof(CinepakContext),
    cinepak_decode_init,
    NULL,
    cinepak_decode_end,
    cinepak_decode_frame,
    CODEC_CAP_DR1,
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -