00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 
00038 #include "libavutil/internal.h"
00039 #include "libavutil/intreadwrite.h"
00040 #include "avcodec.h"
00041 
00042 
00043 static const enum PixelFormat pixfmt_rgb24[] = {
00044     PIX_FMT_BGR24, PIX_FMT_RGB32, PIX_FMT_NONE };
00045 
00046 
00047 
00048 
00049 typedef struct EightBpsContext {
00050     AVCodecContext *avctx;
00051     AVFrame pic;
00052 
00053     unsigned char planes;
00054     unsigned char planemap[4];
00055 
00056     uint32_t pal[256];
00057 } EightBpsContext;
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 static int decode_frame(AVCodecContext *avctx, void *data,
00066                         int *data_size, AVPacket *avpkt)
00067 {
00068     const uint8_t *buf = avpkt->data;
00069     int buf_size       = avpkt->size;
00070     EightBpsContext * const c = avctx->priv_data;
00071     const unsigned char *encoded = buf;
00072     unsigned char *pixptr, *pixptr_end;
00073     unsigned int height = avctx->height; 
00074     unsigned int dlen, p, row;
00075     const unsigned char *lp, *dp;
00076     unsigned char count;
00077     unsigned int planes     = c->planes;
00078     unsigned char *planemap = c->planemap;
00079 
00080     if (c->pic.data[0])
00081         avctx->release_buffer(avctx, &c->pic);
00082 
00083     c->pic.reference    = 0;
00084     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID;
00085     if (avctx->get_buffer(avctx, &c->pic) < 0){
00086         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00087         return -1;
00088     }
00089 
00090     
00091     dp = encoded + planes * (height << 1);
00092 
00093     for (p = 0; p < planes; p++) {
00094         
00095         lp = encoded + p * (height << 1);
00096 
00097         
00098         for (row = 0; row < height; row++) {
00099             pixptr = c->pic.data[0] + row * c->pic.linesize[0] + planemap[p];
00100             pixptr_end = pixptr + c->pic.linesize[0];
00101             dlen = av_be2ne16(*(const unsigned short *)(lp + row * 2));
00102             
00103             while (dlen > 0) {
00104                 if (dp + 1 >= buf + buf_size)
00105                     return -1;
00106                 if ((count = *dp++) <= 127) {
00107                     count++;
00108                     dlen -= count + 1;
00109                     if (pixptr + count * planes > pixptr_end)
00110                         break;
00111                     if (dp + count > buf + buf_size)
00112                         return -1;
00113                     while (count--) {
00114                         *pixptr = *dp++;
00115                         pixptr += planes;
00116                     }
00117                 } else {
00118                     count = 257 - count;
00119                     if (pixptr + count * planes > pixptr_end)
00120                         break;
00121                     while (count--) {
00122                         *pixptr = *dp;
00123                         pixptr += planes;
00124                     }
00125                     dp++;
00126                     dlen -= 2;
00127                 }
00128             }
00129         }
00130     }
00131 
00132     if (avctx->bits_per_coded_sample <= 8) {
00133         const uint8_t *pal = av_packet_get_side_data(avpkt,
00134                                                      AV_PKT_DATA_PALETTE,
00135                                                      NULL);
00136         if (pal) {
00137             c->pic.palette_has_changed = 1;
00138             memcpy(c->pal, pal, AVPALETTE_SIZE);
00139         }
00140 
00141         memcpy (c->pic.data[1], c->pal, AVPALETTE_SIZE);
00142     }
00143 
00144     *data_size = sizeof(AVFrame);
00145     *(AVFrame*)data = c->pic;
00146 
00147     
00148     return buf_size;
00149 }
00150 
00151 
00152 
00153 
00154 
00155 
00156 
00157 static av_cold int decode_init(AVCodecContext *avctx)
00158 {
00159     EightBpsContext * const c = avctx->priv_data;
00160 
00161     c->avctx       = avctx;
00162     c->pic.data[0] = NULL;
00163 
00164     avcodec_get_frame_defaults(&c->pic);
00165     switch (avctx->bits_per_coded_sample) {
00166     case 8:
00167         avctx->pix_fmt = PIX_FMT_PAL8;
00168         c->planes      = 1;
00169         c->planemap[0] = 0; 
00170         break;
00171     case 24:
00172         avctx->pix_fmt = avctx->get_format(avctx, pixfmt_rgb24);
00173         c->planes      = 3;
00174         c->planemap[0] = 2; 
00175         c->planemap[1] = 1; 
00176         c->planemap[2] = 0; 
00177         break;
00178     case 32:
00179         avctx->pix_fmt = PIX_FMT_RGB32;
00180         c->planes      = 4;
00181 #if HAVE_BIGENDIAN
00182         c->planemap[0] = 1; 
00183         c->planemap[1] = 2; 
00184         c->planemap[2] = 3; 
00185         c->planemap[3] = 0; 
00186 #else
00187         c->planemap[0] = 2; 
00188         c->planemap[1] = 1; 
00189         c->planemap[2] = 0; 
00190         c->planemap[3] = 3; 
00191 #endif
00192         break;
00193     default:
00194         av_log(avctx, AV_LOG_ERROR, "Error: Unsupported color depth: %u.\n",
00195                avctx->bits_per_coded_sample);
00196         return -1;
00197     }
00198 
00199     return 0;
00200 }
00201 
00202 
00203 
00204 
00205 
00206 
00207 
00208 
00209 
00210 static av_cold int decode_end(AVCodecContext *avctx)
00211 {
00212     EightBpsContext * const c = avctx->priv_data;
00213 
00214     if (c->pic.data[0])
00215         avctx->release_buffer(avctx, &c->pic);
00216 
00217     return 0;
00218 }
00219 
00220 
00221 
00222 AVCodec ff_eightbps_decoder = {
00223     .name           = "8bps",
00224     .type           = AVMEDIA_TYPE_VIDEO,
00225     .id             = AV_CODEC_ID_8BPS,
00226     .priv_data_size = sizeof(EightBpsContext),
00227     .init           = decode_init,
00228     .close          = decode_end,
00229     .decode         = decode_frame,
00230     .capabilities   = CODEC_CAP_DR1,
00231     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime 8BPS video"),
00232 };