|
|
|
/*
|
|
|
|
* Dirac decoder support via libdirac library
|
|
|
|
* Copyright (c) 2005 BBC, Andrew Kennedy <dirac at rd dot bbc dot co dot uk>
|
|
|
|
* Copyright (c) 2006-2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com >
|
|
|
|
*
|
|
|
|
* 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 <assert.h>
|
|
|
|
|
|
|
|
#include <libdirac_decoder/dirac_parser.h>
|
|
|
|
|
|
|
|
/** contains a single frame returned from Dirac */
|
|
|
|
typedef struct FfmpegDiracDecoderParams {
|
|
|
|
/** decoder handle */
|
|
|
|
dirac_decoder_t* p_decoder;
|
|
|
|
|
|
|
|
/** buffer to hold decoded frame */
|
|
|
|
unsigned char* p_out_frame_buf;
|
|
|
|
} FfmpegDiracDecoderParams;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* returns FFmpeg chroma format
|
|
|
|
*/
|
|
|
|
static enum PixelFormat GetFfmpegChromaFormat(dirac_chroma_t dirac_pix_fmt)
|
|
|
|
{
|
|
|
|
int num_formats = sizeof(ffmpeg_dirac_pixel_format_map) /
|
|
|
|
sizeof(ffmpeg_dirac_pixel_format_map[0]);
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
for (idx = 0; idx < num_formats; ++idx)
|
|
|
|
if (ffmpeg_dirac_pixel_format_map[idx].dirac_pix_fmt == dirac_pix_fmt)
|
|
|
|
return ffmpeg_dirac_pixel_format_map[idx].ff_pix_fmt;
|
|
|
|
return PIX_FMT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static av_cold int libdirac_decode_init(AVCodecContext *avccontext)
|
|
|
|
{
|
|
|
|
|
|
|
|
FfmpegDiracDecoderParams *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;
|
|
|
|
|
|
|
|
FfmpegDiracDecoderParams *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 = GetFfmpegChromaFormat(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)
|
|
|
|
{
|
|
|
|
FfmpegDiracDecoderParams *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(FfmpegDiracDecoderParams),
|
|
|
|
.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"),
|
|
|
|
};
|