/* * Dirac decoder support via libdirac library * Copyright (c) 2005 BBC, Andrew Kennedy * Copyright (c) 2006-2008 BBC, Anuradha Suraparaju * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * Dirac decoder support via libdirac library; more details about the Dirac * project can be found at http://dirac.sourceforge.net/. * The libdirac_decoder library implements Dirac specification version 2.2 * (http://dirac.sourceforge.net/specification.html). */ #include "libavutil/imgutils.h" #include "libdirac.h" #undef NDEBUG #include #include /** contains a single frame returned from Dirac */ typedef struct DiracDecoderParams { /** decoder handle */ dirac_decoder_t* p_decoder; /** buffer to hold decoded frame */ unsigned char* p_out_frame_buf; } DiracDecoderParams; /** * returns FFmpeg chroma format */ static enum PixelFormat get_chroma_format(dirac_chroma_t dirac_pix_fmt) { int num_formats = sizeof(dirac_pixel_format_map) / sizeof(dirac_pixel_format_map[0]); int idx; for (idx = 0; idx < num_formats; ++idx) if (dirac_pixel_format_map[idx].dirac_pix_fmt == dirac_pix_fmt) return dirac_pixel_format_map[idx].ff_pix_fmt; return PIX_FMT_NONE; } static av_cold int libdirac_decode_init(AVCodecContext *avccontext) { DiracDecoderParams *p_dirac_params = avccontext->priv_data; p_dirac_params->p_decoder = dirac_decoder_init(avccontext->debug); if (!p_dirac_params->p_decoder) return -1; return 0; } static int libdirac_decode_frame(AVCodecContext *avccontext, void *data, int *data_size, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; DiracDecoderParams *p_dirac_params = avccontext->priv_data; AVPicture *picture = data; AVPicture pic; int pict_size; unsigned char *buffer[3]; *data_size = 0; if (buf_size > 0) { /* set data to decode into buffer */ dirac_buffer(p_dirac_params->p_decoder, buf, buf + buf_size); if ((buf[4] & 0x08) == 0x08 && (buf[4] & 0x03)) avccontext->has_b_frames = 1; } while (1) { /* parse data and process result */ DecoderState state = dirac_parse(p_dirac_params->p_decoder); switch (state) { case STATE_BUFFER: return buf_size; case STATE_SEQUENCE: { /* tell FFmpeg about sequence details */ dirac_sourceparams_t *src_params = &p_dirac_params->p_decoder->src_params; if (av_image_check_size(src_params->width, src_params->height, 0, avccontext) < 0) { av_log(avccontext, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n", src_params->width, src_params->height); avccontext->height = avccontext->width = 0; return -1; } avccontext->height = src_params->height; avccontext->width = src_params->width; avccontext->pix_fmt = get_chroma_format(src_params->chroma); if (avccontext->pix_fmt == PIX_FMT_NONE) { av_log(avccontext, AV_LOG_ERROR, "Dirac chroma format %d not supported currently\n", src_params->chroma); return -1; } avccontext->time_base.den = src_params->frame_rate.numerator; avccontext->time_base.num = src_params->frame_rate.denominator; /* calculate output dimensions */ avpicture_fill(&pic, NULL, avccontext->pix_fmt, avccontext->width, avccontext->height); pict_size = avpicture_get_size(avccontext->pix_fmt, avccontext->width, avccontext->height); /* allocate output buffer */ if (!p_dirac_params->p_out_frame_buf) p_dirac_params->p_out_frame_buf = av_malloc(pict_size); buffer[0] = p_dirac_params->p_out_frame_buf; buffer[1] = p_dirac_params->p_out_frame_buf + pic.linesize[0] * avccontext->height; buffer[2] = buffer[1] + pic.linesize[1] * src_params->chroma_height; /* tell Dirac about output destination */ dirac_set_buf(p_dirac_params->p_decoder, buffer, NULL); break; } case STATE_SEQUENCE_END: break; case STATE_PICTURE_AVAIL: /* fill picture with current buffer data from Dirac */ avpicture_fill(picture, p_dirac_params->p_out_frame_buf, avccontext->pix_fmt, avccontext->width, avccontext->height); *data_size = sizeof(AVPicture); return buf_size; case STATE_INVALID: return -1; default: break; } } return buf_size; } static av_cold int libdirac_decode_close(AVCodecContext *avccontext) { DiracDecoderParams *p_dirac_params = avccontext->priv_data; dirac_decoder_close(p_dirac_params->p_decoder); av_freep(&p_dirac_params->p_out_frame_buf); return 0; } static void libdirac_flush(AVCodecContext *avccontext) { /* Got a seek request. We will need free memory held in the private * context and free the current Dirac decoder handle and then open * a new decoder handle. */ libdirac_decode_close(avccontext); libdirac_decode_init(avccontext); return; } AVCodec ff_libdirac_decoder = { .name = "libdirac", .type = AVMEDIA_TYPE_VIDEO, .id = CODEC_ID_DIRAC, .priv_data_size = sizeof(DiracDecoderParams), .init = libdirac_decode_init, .close = libdirac_decode_close, .decode = libdirac_decode_frame, .capabilities = CODEC_CAP_DELAY, .flush = libdirac_flush, .long_name = NULL_IF_CONFIG_SMALL("libdirac Dirac 2.2"), };