1/*
2 * Dirac decoder support via libdirac library
3 * Copyright (c) 2005 BBC, Andrew Kennedy <dirac at rd dot bbc dot co dot uk>
4 * Copyright (c) 2006-2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com >
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23/**
24* @file
25* Dirac decoder support via libdirac library; more details about the Dirac
26* project can be found at http://dirac.sourceforge.net/.
27* The libdirac_decoder library implements Dirac specification version 2.2
28* (http://dirac.sourceforge.net/specification.html).
29*/
30
31#include "libdirac.h"
32
33#undef NDEBUG
34#include <assert.h>
35
36#include <libdirac_decoder/dirac_parser.h>
37
38/** contains a single frame returned from Dirac */
39typedef struct FfmpegDiracDecoderParams {
40    /** decoder handle */
41    dirac_decoder_t* p_decoder;
42
43    /** buffer to hold decoded frame */
44    unsigned char* p_out_frame_buf;
45} FfmpegDiracDecoderParams;
46
47
48/**
49* returns FFmpeg chroma format
50*/
51static enum PixelFormat GetFfmpegChromaFormat(dirac_chroma_t dirac_pix_fmt)
52{
53    int num_formats = sizeof(ffmpeg_dirac_pixel_format_map) /
54                      sizeof(ffmpeg_dirac_pixel_format_map[0]);
55    int idx;
56
57    for (idx = 0; idx < num_formats; ++idx)
58        if (ffmpeg_dirac_pixel_format_map[idx].dirac_pix_fmt == dirac_pix_fmt)
59            return ffmpeg_dirac_pixel_format_map[idx].ff_pix_fmt;
60    return PIX_FMT_NONE;
61}
62
63static av_cold int libdirac_decode_init(AVCodecContext *avccontext)
64{
65
66    FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data;
67    p_dirac_params->p_decoder =  dirac_decoder_init(avccontext->debug);
68
69    if (!p_dirac_params->p_decoder)
70        return -1;
71
72    return 0;
73}
74
75static int libdirac_decode_frame(AVCodecContext *avccontext,
76                                 void *data, int *data_size,
77                                 AVPacket *avpkt)
78{
79    const uint8_t *buf = avpkt->data;
80    int buf_size = avpkt->size;
81
82    FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data;
83    AVPicture *picture = data;
84    AVPicture pic;
85    int pict_size;
86    unsigned char *buffer[3];
87
88    *data_size = 0;
89
90    if (buf_size > 0) {
91        /* set data to decode into buffer */
92        dirac_buffer(p_dirac_params->p_decoder, buf, buf + buf_size);
93        if ((buf[4] & 0x08) == 0x08 && (buf[4] & 0x03))
94            avccontext->has_b_frames = 1;
95    }
96    while (1) {
97         /* parse data and process result */
98        DecoderState state = dirac_parse(p_dirac_params->p_decoder);
99        switch (state) {
100        case STATE_BUFFER:
101            return buf_size;
102
103        case STATE_SEQUENCE:
104        {
105            /* tell FFmpeg about sequence details */
106            dirac_sourceparams_t *src_params = &p_dirac_params->p_decoder->src_params;
107
108            if (avcodec_check_dimensions(avccontext, src_params->width,
109                                         src_params->height) < 0) {
110                av_log(avccontext, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n",
111                       src_params->width, src_params->height);
112                avccontext->height = avccontext->width = 0;
113                return -1;
114            }
115
116            avccontext->height = src_params->height;
117            avccontext->width  = src_params->width;
118
119            avccontext->pix_fmt = GetFfmpegChromaFormat(src_params->chroma);
120            if (avccontext->pix_fmt == PIX_FMT_NONE) {
121                av_log(avccontext, AV_LOG_ERROR,
122                       "Dirac chroma format %d not supported currently\n",
123                       src_params->chroma);
124                return -1;
125            }
126
127            avccontext->time_base.den = src_params->frame_rate.numerator;
128            avccontext->time_base.num = src_params->frame_rate.denominator;
129
130            /* calculate output dimensions */
131            avpicture_fill(&pic, NULL, avccontext->pix_fmt,
132                           avccontext->width, avccontext->height);
133
134            pict_size = avpicture_get_size(avccontext->pix_fmt,
135                                           avccontext->width,
136                                           avccontext->height);
137
138            /* allocate output buffer */
139            if (!p_dirac_params->p_out_frame_buf)
140                p_dirac_params->p_out_frame_buf = av_malloc(pict_size);
141            buffer[0] = p_dirac_params->p_out_frame_buf;
142            buffer[1] = p_dirac_params->p_out_frame_buf +
143                        pic.linesize[0] * avccontext->height;
144            buffer[2] = buffer[1] +
145                        pic.linesize[1] * src_params->chroma_height;
146
147            /* tell Dirac about output destination */
148            dirac_set_buf(p_dirac_params->p_decoder, buffer, NULL);
149            break;
150        }
151        case STATE_SEQUENCE_END:
152            break;
153
154        case STATE_PICTURE_AVAIL:
155            /* fill picture with current buffer data from Dirac */
156            avpicture_fill(picture, p_dirac_params->p_out_frame_buf,
157                           avccontext->pix_fmt,
158                           avccontext->width, avccontext->height);
159            *data_size = sizeof(AVPicture);
160            return buf_size;
161
162        case STATE_INVALID:
163            return -1;
164
165        default:
166            break;
167        }
168    }
169
170    return buf_size;
171}
172
173
174static av_cold int libdirac_decode_close(AVCodecContext *avccontext)
175{
176    FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data;
177    dirac_decoder_close(p_dirac_params->p_decoder);
178
179    av_freep(&p_dirac_params->p_out_frame_buf);
180
181    return 0;
182}
183
184static void libdirac_flush(AVCodecContext *avccontext)
185{
186    /* Got a seek request. We will need free memory held in the private
187     * context and free the current Dirac decoder handle and then open
188     * a new decoder handle. */
189    libdirac_decode_close(avccontext);
190    libdirac_decode_init(avccontext);
191    return;
192}
193
194
195
196AVCodec libdirac_decoder = {
197    "libdirac",
198    AVMEDIA_TYPE_VIDEO,
199    CODEC_ID_DIRAC,
200    sizeof(FfmpegDiracDecoderParams),
201    libdirac_decode_init,
202    NULL,
203    libdirac_decode_close,
204    libdirac_decode_frame,
205    CODEC_CAP_DELAY,
206    .flush = libdirac_flush,
207    .long_name = NULL_IF_CONFIG_SMALL("libdirac Dirac 2.2"),
208};
209