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 } BethsoftvidContext;
00038
00039 static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx)
00040 {
00041 BethsoftvidContext *vid = avctx->priv_data;
00042 avcodec_get_frame_defaults(&vid->frame);
00043 vid->frame.reference = 3;
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(AVFrame * frame, const uint8_t * palette_buffer, int buf_size)
00051 {
00052 uint32_t * palette = (uint32_t *)frame->data[1];
00053 int a;
00054
00055 if (buf_size < 256*3)
00056 return AVERROR_INVALIDDATA;
00057
00058 for(a = 0; a < 256; a++){
00059 palette[a] = 0xFF << 24 | AV_RB24(&palette_buffer[a * 3]) * 4;
00060 palette[a] |= palette[a] >> 6 & 0x30303;
00061 }
00062 frame->palette_has_changed = 1;
00063 return 256*3;
00064 }
00065
00066 static int bethsoftvid_decode_frame(AVCodecContext *avctx,
00067 void *data, int *data_size,
00068 AVPacket *avpkt)
00069 {
00070 const uint8_t *buf = avpkt->data;
00071 int buf_size = avpkt->size;
00072 BethsoftvidContext * vid = avctx->priv_data;
00073 char block_type;
00074 uint8_t * dst;
00075 uint8_t * frame_end;
00076 int remaining = avctx->width;
00077 const int wrap_to_next_line = vid->frame.linesize[0] - avctx->width;
00078 int code;
00079 int yoffset;
00080
00081 if (avctx->reget_buffer(avctx, &vid->frame)) {
00082 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00083 return -1;
00084 }
00085 dst = vid->frame.data[0];
00086 frame_end = vid->frame.data[0] + vid->frame.linesize[0] * avctx->height;
00087
00088 switch(block_type = *buf++){
00089 case PALETTE_BLOCK:
00090 return set_palette(&vid->frame, buf, buf_size);
00091 case VIDEO_YOFF_P_FRAME:
00092 yoffset = bytestream_get_le16(&buf);
00093 if(yoffset >= avctx->height)
00094 return -1;
00095 dst += vid->frame.linesize[0] * yoffset;
00096 }
00097
00098
00099 while((code = *buf++)){
00100 int length = code & 0x7f;
00101
00102
00103 while(length > remaining){
00104 if(code < 0x80)
00105 bytestream_get_buffer(&buf, dst, remaining);
00106 else if(block_type == VIDEO_I_FRAME)
00107 memset(dst, buf[0], 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 bytestream_get_buffer(&buf, dst, length);
00118 else if(block_type == VIDEO_I_FRAME)
00119 memset(dst, *buf++, length);
00120 remaining -= length;
00121 dst += length;
00122 }
00123 end:
00124
00125 *data_size = sizeof(AVFrame);
00126 *(AVFrame*)data = vid->frame;
00127
00128 return buf_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 };