libavcodec/libutvideo.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Derek Buitenhuis
00003  *
00004  * This file is part of FFmpeg.
00005  *
00006  * FFmpeg is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public
00008  * License as published by the Free Software Foundation;
00009  * version 2 of the License.
00010  *
00011  * FFmpeg is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public
00017  * License along with FFmpeg; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00027 extern "C" {
00028 #include "avcodec.h"
00029 }
00030 
00031 #include <stdlib.h>
00032 #include <utvideo/utvideo.h>
00033 #include <utvideo/Codec.h>
00034 
00035 #include "get_bits.h"
00036 
00037 typedef struct {
00038     uint32_t version;
00039     uint32_t original_format;
00040     uint32_t frameinfo_size;
00041     uint32_t flags;
00042 } UtVideoExtra;
00043 
00044 typedef struct {
00045     CCodec *codec;
00046     unsigned int buf_size;
00047     uint8_t *output;
00048 } UtVideoContext;
00049 
00050 static av_cold int utvideo_decode_init(AVCodecContext *avctx)
00051 {
00052     UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
00053     UtVideoExtra info;
00054     int format;
00055     int begin_ret;
00056 
00057     if (avctx->extradata_size != 4*4) {
00058         av_log(avctx, AV_LOG_ERROR, "Extradata size mismatch.\n");
00059         return -1;
00060     }
00061 
00062     /* Read extradata */
00063     info.version = AV_RL32(avctx->extradata);
00064     info.original_format = AV_RL32(avctx->extradata + 4);
00065     info.frameinfo_size = AV_RL32(avctx->extradata + 8);
00066     info.flags = AV_RL32(avctx->extradata + 12);
00067 
00068     /* Pick format based on FOURCC */
00069     switch (avctx->codec_tag) {
00070     case MKTAG('U', 'L', 'Y', '0'):
00071         avctx->pix_fmt = PIX_FMT_YUV420P;
00072         format = UTVF_YV12;
00073         break;
00074     case MKTAG('U', 'L', 'Y', '2'):
00075         avctx->pix_fmt = PIX_FMT_YUYV422;
00076         format = UTVF_YUY2;
00077         break;
00078     case MKTAG('U', 'L', 'R', 'G'):
00079         avctx->pix_fmt = PIX_FMT_BGR24;
00080         format = UTVF_RGB24_WIN;
00081         break;
00082     case MKTAG('U', 'L', 'R', 'A'):
00083         avctx->pix_fmt = PIX_FMT_RGB32;
00084         format = UTVF_RGB32_WIN;
00085         break;
00086     default:
00087         av_log(avctx, AV_LOG_ERROR,
00088               "Not a Ut Video FOURCC: %X\n", avctx->codec_tag);
00089         return -1;
00090     }
00091 
00092     /* Only allocate the buffer once */
00093     utv->buf_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
00094     utv->output = (uint8_t *)av_malloc(utv->buf_size * sizeof(uint8_t));
00095 
00096     if (utv->output == NULL) {
00097         av_log(avctx, AV_LOG_ERROR, "Unable to allocate output buffer.\n");
00098         return -1;
00099     }
00100 
00101     /* Allocate the output frame */
00102     avctx->coded_frame = avcodec_alloc_frame();
00103 
00104     /* Ut Video only supports 8-bit */
00105     avctx->bits_per_raw_sample = 8;
00106 
00107     /* Is it interlaced? */
00108     avctx->coded_frame->interlaced_frame = info.flags & 0x800 ? 1 : 0;
00109 
00110     /* Apparently Ut Video doesn't store this info... */
00111     avctx->coded_frame->top_field_first = 1;
00112 
00113     /*
00114      * Create a Ut Video instance. Since the function wants
00115      * an "interface name" string, pass it the name of the lib.
00116      */
00117     utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec");
00118 
00119     /* Initialize Decoding */
00120     begin_ret = utv->codec->DecodeBegin(format, avctx->width, avctx->height,
00121                             CBGROSSWIDTH_WINDOWS, &info, sizeof(UtVideoExtra));
00122 
00123     /* Check to see if the decoder initlized properly */
00124     if (begin_ret != 0) {
00125         av_log(avctx, AV_LOG_ERROR,
00126                "Could not initialize decoder: %d\n", begin_ret);
00127         return -1;
00128     }
00129 
00130     return 0;
00131 }
00132 
00133 static int utvideo_decode_frame(AVCodecContext *avctx, void *data,
00134                                 int *data_size, AVPacket *avpkt)
00135 {
00136     UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
00137     AVFrame *pic = avctx->coded_frame;
00138     int w = avctx->width, h = avctx->height;
00139 
00140     /* Set flags */
00141     pic->reference = 0;
00142     pic->pict_type = AV_PICTURE_TYPE_I;
00143     pic->key_frame = 1;
00144 
00145     /* Decode the frame */
00146     utv->codec->DecodeFrame(utv->output, avpkt->data, true);
00147 
00148     /* Set the output data depending on the colorspace */
00149     switch (avctx->pix_fmt) {
00150     case PIX_FMT_YUV420P:
00151         pic->linesize[0] = w;
00152         pic->linesize[1] = pic->linesize[2] = w / 2;
00153         pic->data[0] = utv->output;
00154         pic->data[2] = utv->output + (w * h);
00155         pic->data[1] = pic->data[2] + (w * h / 4);
00156         break;
00157     case PIX_FMT_YUYV422:
00158         pic->linesize[0] = w * 2;
00159         pic->data[0] = utv->output;
00160         break;
00161     case PIX_FMT_BGR24:
00162     case PIX_FMT_RGB32:
00163         /* Make the linesize negative, since Ut Video uses bottom-up BGR */
00164         pic->linesize[0] = -1 * w * (avctx->pix_fmt == PIX_FMT_BGR24 ? 3 : 4);
00165         pic->data[0] = utv->output + utv->buf_size + pic->linesize[0];
00166         break;
00167     }
00168 
00169     *data_size = sizeof(AVFrame);
00170     *(AVFrame *)data = *pic;
00171 
00172     return avpkt->size;
00173 }
00174 
00175 static av_cold int utvideo_decode_close(AVCodecContext *avctx)
00176 {
00177     UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
00178 
00179     /* Free output */
00180     av_freep(&avctx->coded_frame);
00181     av_freep(&utv->output);
00182 
00183     /* Finish decoding and clean up the instance */
00184     utv->codec->DecodeEnd();
00185     CCodec::DeleteInstance(utv->codec);
00186 
00187     return 0;
00188 }
00189 
00190 AVCodec ff_libutvideo_decoder = {
00191     "libutvideo",
00192     AVMEDIA_TYPE_VIDEO,
00193     CODEC_ID_UTVIDEO,
00194     sizeof(UtVideoContext),
00195     utvideo_decode_init,
00196     NULL,
00197     utvideo_decode_close,
00198     utvideo_decode_frame,
00199     NULL,
00200     NULL,
00201     NULL,
00202     NULL,
00203     NULL,
00204     NULL_IF_CONFIG_SMALL("Ut Video"),
00205 };