yading@10: /* yading@10: * Copyright (c) 2011 Derek Buitenhuis yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU General Public yading@10: * License as published by the Free Software Foundation; yading@10: * version 2 of the License. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * Known FOURCCs: yading@10: * 'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA) yading@10: */ yading@10: yading@10: extern "C" { yading@10: #include "avcodec.h" yading@10: } yading@10: yading@10: #include "libutvideo.h" yading@10: #include "get_bits.h" yading@10: yading@10: static av_cold int utvideo_decode_init(AVCodecContext *avctx) yading@10: { yading@10: UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; yading@10: UtVideoExtra info; yading@10: int format; yading@10: int begin_ret; yading@10: yading@10: if (avctx->extradata_size != 4*4) { yading@10: av_log(avctx, AV_LOG_ERROR, "Extradata size mismatch.\n"); yading@10: return -1; yading@10: } yading@10: yading@10: /* Read extradata */ yading@10: info.version = AV_RL32(avctx->extradata); yading@10: info.original_format = AV_RL32(avctx->extradata + 4); yading@10: info.frameinfo_size = AV_RL32(avctx->extradata + 8); yading@10: info.flags = AV_RL32(avctx->extradata + 12); yading@10: yading@10: /* Pick format based on FOURCC */ yading@10: switch (avctx->codec_tag) { yading@10: case MKTAG('U', 'L', 'Y', '0'): yading@10: avctx->pix_fmt = AV_PIX_FMT_YUV420P; yading@10: format = UTVF_YV12; yading@10: break; yading@10: case MKTAG('U', 'L', 'Y', '2'): yading@10: avctx->pix_fmt = AV_PIX_FMT_YUYV422; yading@10: format = UTVF_YUY2; yading@10: break; yading@10: case MKTAG('U', 'L', 'R', 'G'): yading@10: avctx->pix_fmt = AV_PIX_FMT_BGR24; yading@10: format = UTVF_NFCC_BGR_BU; yading@10: break; yading@10: case MKTAG('U', 'L', 'R', 'A'): yading@10: avctx->pix_fmt = AV_PIX_FMT_RGB32; yading@10: format = UTVF_NFCC_BGRA_BU; yading@10: break; yading@10: default: yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "Not a Ut Video FOURCC: %X\n", avctx->codec_tag); yading@10: return -1; yading@10: } yading@10: yading@10: /* Only allocate the buffer once */ yading@10: utv->buf_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height); yading@10: utv->buffer = (uint8_t *)av_malloc(utv->buf_size * sizeof(uint8_t)); yading@10: yading@10: if (utv->buffer == NULL) { yading@10: av_log(avctx, AV_LOG_ERROR, "Unable to allocate output buffer.\n"); yading@10: return -1; yading@10: } yading@10: yading@10: /* Allocate the output frame */ yading@10: avctx->coded_frame = avcodec_alloc_frame(); yading@10: yading@10: /* Ut Video only supports 8-bit */ yading@10: avctx->bits_per_raw_sample = 8; yading@10: yading@10: /* Is it interlaced? */ yading@10: avctx->coded_frame->interlaced_frame = info.flags & 0x800 ? 1 : 0; yading@10: yading@10: /* Apparently Ut Video doesn't store this info... */ yading@10: avctx->coded_frame->top_field_first = 1; yading@10: yading@10: /* yading@10: * Create a Ut Video instance. Since the function wants yading@10: * an "interface name" string, pass it the name of the lib. yading@10: */ yading@10: utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec"); yading@10: yading@10: /* Initialize Decoding */ yading@10: begin_ret = utv->codec->DecodeBegin(format, avctx->width, avctx->height, yading@10: CBGROSSWIDTH_WINDOWS, &info, sizeof(UtVideoExtra)); yading@10: yading@10: /* Check to see if the decoder initlized properly */ yading@10: if (begin_ret != 0) { yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "Could not initialize decoder: %d\n", begin_ret); yading@10: return -1; yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static int utvideo_decode_frame(AVCodecContext *avctx, void *data, yading@10: int *got_frame, AVPacket *avpkt) yading@10: { yading@10: UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; yading@10: AVFrame *pic = avctx->coded_frame; yading@10: int w = avctx->width, h = avctx->height; yading@10: yading@10: /* Set flags */ yading@10: pic->reference = 0; yading@10: pic->pict_type = AV_PICTURE_TYPE_I; yading@10: pic->key_frame = 1; yading@10: yading@10: /* Decode the frame */ yading@10: utv->codec->DecodeFrame(utv->buffer, avpkt->data, true); yading@10: yading@10: /* Set the output data depending on the colorspace */ yading@10: switch (avctx->pix_fmt) { yading@10: case AV_PIX_FMT_YUV420P: yading@10: pic->linesize[0] = w; yading@10: pic->linesize[1] = pic->linesize[2] = w / 2; yading@10: pic->data[0] = utv->buffer; yading@10: pic->data[2] = utv->buffer + (w * h); yading@10: pic->data[1] = pic->data[2] + (w * h / 4); yading@10: break; yading@10: case AV_PIX_FMT_YUYV422: yading@10: pic->linesize[0] = w * 2; yading@10: pic->data[0] = utv->buffer; yading@10: break; yading@10: case AV_PIX_FMT_BGR24: yading@10: case AV_PIX_FMT_RGB32: yading@10: /* Make the linesize negative, since Ut Video uses bottom-up BGR */ yading@10: pic->linesize[0] = -1 * w * (avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4); yading@10: pic->data[0] = utv->buffer + utv->buf_size + pic->linesize[0]; yading@10: break; yading@10: } yading@10: yading@10: *got_frame = 1; yading@10: *(AVFrame *)data = *pic; yading@10: yading@10: return avpkt->size; yading@10: } yading@10: yading@10: static av_cold int utvideo_decode_close(AVCodecContext *avctx) yading@10: { yading@10: UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; yading@10: yading@10: /* Free output */ yading@10: av_freep(&avctx->coded_frame); yading@10: av_freep(&utv->buffer); yading@10: yading@10: /* Finish decoding and clean up the instance */ yading@10: utv->codec->DecodeEnd(); yading@10: CCodec::DeleteInstance(utv->codec); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: AVCodec ff_libutvideo_decoder = { yading@10: "libutvideo", yading@10: NULL_IF_CONFIG_SMALL("Ut Video"), yading@10: AVMEDIA_TYPE_VIDEO, yading@10: AV_CODEC_ID_UTVIDEO, yading@10: 0, //capabilities yading@10: NULL, //supported_framerates yading@10: NULL, //pix_fmts yading@10: NULL, //supported_samplerates yading@10: NULL, //sample_fmts yading@10: NULL, //channel_layouts yading@10: 0, //max_lowres yading@10: NULL, //priv_class yading@10: NULL, //profiles yading@10: sizeof(UtVideoContext), yading@10: NULL, //next yading@10: NULL, //init_thread_copy yading@10: NULL, //update_thread_context yading@10: NULL, //defaults yading@10: NULL, //init_static_data yading@10: utvideo_decode_init, yading@10: NULL, //encode yading@10: NULL, //encode2 yading@10: utvideo_decode_frame, yading@10: utvideo_decode_close, yading@10: };