Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00030 #include "libavutil/common.h"
00031 #include "dsputil.h"
00032 #include "bethsoftvideo.h"
00033 #include "bytestream.h"
00034
00035 typedef struct BethsoftvidContext {
00036 AVFrame frame;
00037 GetByteContext g;
00038 } BethsoftvidContext;
00039
00040 static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx)
00041 {
00042 BethsoftvidContext *vid = avctx->priv_data;
00043 vid->frame.reference = 1;
00044 vid->frame.buffer_hints = FF_BUFFER_HINTS_VALID |
00045 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00046 avctx->pix_fmt = PIX_FMT_PAL8;
00047 return 0;
00048 }
00049
00050 static int set_palette(BethsoftvidContext *ctx)
00051 {
00052 uint32_t *palette = (uint32_t *)ctx->frame.data[1];
00053 int a;
00054
00055 if (bytestream2_get_bytes_left(&ctx->g) < 256*3)
00056 return AVERROR_INVALIDDATA;
00057
00058 for(a = 0; a < 256; a++){
00059 palette[a] = bytestream2_get_be24u(&ctx->g) * 4;
00060 }
00061 ctx->frame.palette_has_changed = 1;
00062 return 256*3;
00063 }
00064
00065 static int bethsoftvid_decode_frame(AVCodecContext *avctx,
00066 void *data, int *data_size,
00067 AVPacket *avpkt)
00068 {
00069 BethsoftvidContext * vid = avctx->priv_data;
00070 char block_type;
00071 uint8_t * dst;
00072 uint8_t * frame_end;
00073 int remaining = avctx->width;
00074 const int wrap_to_next_line = vid->frame.linesize[0] - avctx->width;
00075 int code;
00076 int yoffset;
00077
00078 if (avctx->reget_buffer(avctx, &vid->frame)) {
00079 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00080 return -1;
00081 }
00082
00083 bytestream2_init(&vid->g, avpkt->data, avpkt->size);
00084 dst = vid->frame.data[0];
00085 frame_end = vid->frame.data[0] + vid->frame.linesize[0] * avctx->height;
00086
00087 switch(block_type = bytestream2_get_byte(&vid->g)){
00088 case PALETTE_BLOCK: {
00089 return set_palette(vid);
00090 }
00091 case VIDEO_YOFF_P_FRAME:
00092 yoffset = bytestream2_get_le16(&vid->g);
00093 if(yoffset >= avctx->height)
00094 return -1;
00095 dst += vid->frame.linesize[0] * yoffset;
00096 }
00097
00098
00099 while((code = bytestream2_get_byte(&vid->g))){
00100 int length = code & 0x7f;
00101
00102
00103 while(length > remaining){
00104 if(code < 0x80)
00105 bytestream2_get_buffer(&vid->g, dst, remaining);
00106 else if(block_type == VIDEO_I_FRAME)
00107 memset(dst, bytestream2_peek_byte(&vid->g), remaining);
00108 length -= remaining;
00109 dst += remaining + wrap_to_next_line;
00110 remaining = avctx->width;
00111 if(dst == frame_end)
00112 goto end;
00113 }
00114
00115
00116 if(code < 0x80)
00117 bytestream2_get_buffer(&vid->g, dst, length);
00118 else if(block_type == VIDEO_I_FRAME)
00119 memset(dst, bytestream2_get_byte(&vid->g), length);
00120 remaining -= length;
00121 dst += length;
00122 }
00123 end:
00124
00125 *data_size = sizeof(AVFrame);
00126 *(AVFrame*)data = vid->frame;
00127
00128 return avpkt->size;
00129 }
00130
00131 static av_cold int bethsoftvid_decode_end(AVCodecContext *avctx)
00132 {
00133 BethsoftvidContext * vid = avctx->priv_data;
00134 if(vid->frame.data[0])
00135 avctx->release_buffer(avctx, &vid->frame);
00136 return 0;
00137 }
00138
00139 AVCodec ff_bethsoftvid_decoder = {
00140 .name = "bethsoftvid",
00141 .type = AVMEDIA_TYPE_VIDEO,
00142 .id = CODEC_ID_BETHSOFTVID,
00143 .priv_data_size = sizeof(BethsoftvidContext),
00144 .init = bethsoftvid_decode_init,
00145 .close = bethsoftvid_decode_end,
00146 .decode = bethsoftvid_decode_frame,
00147 .capabilities = CODEC_CAP_DR1,
00148 .long_name = NULL_IF_CONFIG_SMALL("Bethesda VID video"),
00149 };