rawvideo.c 10.2 KB
Newer Older
1
/*****************************************************************************
2
 * rawvideo.c: Pseudo video decoder/packetizer for raw video data
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
5
 * $Id$
6 7 8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9 10 11
 * This program 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
12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
27 28 29 30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
33
#include <vlc_codec.h>
34

35
/*****************************************************************************
36
 * decoder_sys_t : raw video decoder descriptor
37
 *****************************************************************************/
38
struct decoder_sys_t
39
{
40 41 42
    /*
     * Input properties
     */
43 44 45
    size_t size;
    unsigned pitches[PICTURE_PLANE_MAX];
    unsigned lines[PICTURE_PLANE_MAX];
46

47 48 49
    /*
     * Common properties
     */
50
    date_t pts;
51
};
52

53 54 55
/****************************************************************************
 * Local prototypes
 ****************************************************************************/
56 57
static int  OpenDecoder   ( vlc_object_t * );
static int  OpenPacketizer( vlc_object_t * );
58
static void CloseCommon   ( vlc_object_t * );
59 60 61 62

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
63 64
vlc_module_begin ()
    set_description( N_("Pseudo raw video decoder") )
65
    set_capability( "video decoder", 50 )
66 67
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_VCODEC )
68
    set_callbacks( OpenDecoder, CloseCommon )
69

70 71 72
    add_submodule ()
    set_description( N_("Pseudo raw video packetizer") )
    set_capability( "packetizer", 100 )
73
    set_callbacks( OpenPacketizer, CloseCommon )
74
vlc_module_end ()
75

76 77 78
/**
 * Common initialization for decoder and packetizer
 */
79
static int OpenCommon( decoder_t *p_dec )
80
{
81 82 83 84 85
    const vlc_chroma_description_t *dsc =
        vlc_fourcc_GetChromaDescription( p_dec->fmt_in.i_codec );
    if( dsc == NULL || dsc->plane_count == 0 )
        return VLC_EGENERIC;

86
    if( p_dec->fmt_in.video.i_width <= 0 || p_dec->fmt_in.video.i_height == 0 )
87
    {
88 89 90
        msg_Err( p_dec, "invalid display size %dx%d",
                 p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height );
        return VLC_EGENERIC;
91
    }
92 93

    /* Allocate the memory needed to store the decoder's structure */
94 95
    decoder_sys_t *p_sys = calloc(1, sizeof(*p_sys));
    if( unlikely(p_sys == NULL) )
96
        return VLC_ENOMEM;
97

98 99 100 101
    if( !p_dec->fmt_in.video.i_visible_width )
        p_dec->fmt_in.video.i_visible_width = p_dec->fmt_in.video.i_width;
    if( !p_dec->fmt_in.video.i_visible_height )
        p_dec->fmt_in.video.i_visible_height = p_dec->fmt_in.video.i_height;
102

103
    es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
104 105 106 107

    if( p_dec->fmt_out.video.i_frame_rate == 0 ||
        p_dec->fmt_out.video.i_frame_rate_base == 0)
    {
108 109 110 111
        msg_Warn( p_dec, "invalid frame rate %d/%d, using 25 fps instead",
                  p_dec->fmt_out.video.i_frame_rate,
                  p_dec->fmt_out.video.i_frame_rate_base);
        date_Init( &p_sys->pts, 25, 1 );
112
    }
113 114 115
    else
        date_Init( &p_sys->pts, p_dec->fmt_out.video.i_frame_rate,
                    p_dec->fmt_out.video.i_frame_rate_base );
116

117
    for( unsigned i = 0; i < dsc->plane_count; i++ )
118
    {
119 120 121 122 123 124 125 126
        unsigned pitch = p_dec->fmt_in.video.i_width * dsc->pixel_size
                         * dsc->p[i].w.num / dsc->p[i].w.den;
        unsigned lines = p_dec->fmt_in.video.i_height
                         * dsc->p[i].h.num / dsc->p[i].h.den;

        p_sys->pitches[i] = pitch;
        p_sys->lines[i] = lines;
        p_sys->size += pitch * lines;
127
    }
128

129
    p_dec->p_sys           = p_sys;
130 131 132
    return VLC_SUCCESS;
}

133 134 135 136 137 138 139 140 141 142
/*****************************************************************************
 * Flush:
 *****************************************************************************/
static void Flush( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    date_Set( &p_sys->pts, VLC_TS_INVALID );
}

143
/****************************************************************************
144
 * DecodeBlock: the whole thing
145
 ****************************************************************************
146
 * This function must be fed with complete frames.
147
 ****************************************************************************/
148
static block_t *DecodeBlock( decoder_t *p_dec, block_t *p_block )
149
{
150
    decoder_sys_t *p_sys = p_dec->p_sys;
151

152 153
    if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED|BLOCK_FLAG_DISCONTINUITY) )
    {
154
        date_Set( &p_sys->pts, p_block->i_dts );
155 156 157 158 159 160
        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
        {
            block_Release( p_block );
            return NULL;
        }
    }
161

162 163
    if( p_block->i_pts <= VLC_TS_INVALID && p_block->i_dts <= VLC_TS_INVALID &&
        !date_Get( &p_sys->pts ) )
164
    {
165 166
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
167
        return NULL;
168
    }
169

170
    /* Date management: If there is a pts avaliable, use that. */
171
    if( p_block->i_pts > VLC_TS_INVALID )
172 173 174
    {
        date_Set( &p_sys->pts, p_block->i_pts );
    }
175
    else if( p_block->i_dts > VLC_TS_INVALID )
176
    {
177 178 179 180 181
        /* NB, davidf doesn't quite agree with this in general, it is ok
         * for rawvideo since it is in order (ie pts=dts), however, it
         * may not be ok for an out-of-order codec, so don't copy this
         * without thinking */
        date_Set( &p_sys->pts, p_block->i_dts );
182 183
    }

184
    if( p_block->i_buffer < p_sys->size )
185
    {
186
        msg_Warn( p_dec, "invalid frame size (%zu < %zu)",
187
                  p_block->i_buffer, p_sys->size );
188 189

        block_Release( p_block );
190
        return NULL;
191 192
    }

193
    return p_block;
194
}
195

196 197 198 199
/*****************************************************************************
 * FillPicture:
 *****************************************************************************/
static void FillPicture( decoder_t *p_dec, block_t *p_block, picture_t *p_pic )
200
{
201
    decoder_sys_t *p_sys = p_dec->p_sys;
202
    const uint8_t *p_src = p_block->p_buffer;
203

204 205 206 207 208
    for( int i = 0; i < p_pic->i_planes; i++ )
    {
        uint8_t *p_dst = p_pic->p[i].p_pixels;

        for( int x = 0; x < p_pic->p[i].i_visible_lines; x++ )
209
        {
210 211 212
            memcpy( p_dst, p_src, p_pic->p[i].i_visible_pitch );
            p_src += p_sys->pitches[i];
            p_dst += p_pic->p[i].i_pitch;
213 214
        }

215 216 217
        p_src += p_sys->pitches[i]
               * (p_sys->lines[i] - p_pic->p[i].i_visible_lines);
    }
218 219 220
}

/*****************************************************************************
221
 * DecodeFrame: decodes a video frame.
222
 *****************************************************************************/
223
static int DecodeFrame( decoder_t *p_dec, block_t *p_block )
224
{
225 226 227 228
    if( p_block == NULL ) /* No Drain */
        return VLCDEC_SUCCESS;

    p_block = DecodeBlock( p_dec, p_block );
229
    if( p_block == NULL )
230
        return VLCDEC_SUCCESS;
231

232
    decoder_sys_t *p_sys = p_dec->p_sys;
233

234
    /* Get a new picture */
235 236 237
    picture_t *p_pic = NULL;
    if( !decoder_UpdateVideoFormat( p_dec ) )
        p_pic = decoder_NewPicture( p_dec );
238
    if( p_pic == NULL )
239
    {
240
        block_Release( p_block );
241
        return VLCDEC_SUCCESS;
242
    }
243 244 245

    FillPicture( p_dec, p_block, p_pic );

246 247 248 249
    /* Date management: 1 frame per packet */
    p_pic->date = date_Get( &p_dec->p_sys->pts );
    date_Increment( &p_sys->pts, 1 );

250 251 252
    if( p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK )
    {
        p_pic->b_progressive = false;
253
        p_pic->i_nb_fields = (p_block->i_flags & BLOCK_FLAG_SINGLE_FIELD) ? 1 : 2;
254 255 256 257 258 259 260
        if( p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST )
            p_pic->b_top_field_first = true;
        else
            p_pic->b_top_field_first = false;
    }
    else
        p_pic->b_progressive = true;
261

262
    block_Release( p_block );
263 264
    decoder_QueueVideo( p_dec, p_pic );
    return VLCDEC_SUCCESS;
265
}
266

267 268 269 270
static int OpenDecoder( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t *)p_this;

271
    int ret = OpenCommon( p_dec );
272
    if( ret == VLC_SUCCESS )
273
    {
274 275
        p_dec->pf_decode = DecodeFrame;
        p_dec->pf_flush  = Flush;
276
    }
277 278 279
    return ret;
}

280 281 282
/*****************************************************************************
 * SendFrame: send a video frame to the stream output.
 *****************************************************************************/
283
static block_t *SendFrame( decoder_t *p_dec, block_t **pp_block )
284
{
285 286 287 288 289 290 291 292 293
    if( pp_block == NULL ) /* No Drain */
        return NULL;

    block_t *p_block = *pp_block;
    if( p_block == NULL )
        return NULL;
    *pp_block = NULL;

    p_block = DecodeBlock( p_dec, p_block );
294 295 296
    if( p_block == NULL )
        return NULL;

297
    decoder_sys_t *p_sys = p_dec->p_sys;
298

299
    /* Date management: 1 frame per packet */
300
    p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts );
301
    date_Increment( &p_sys->pts, 1 );
302
    return p_block;
303
}
304

305 306 307 308
static int OpenPacketizer( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t *)p_this;

309
    int ret = OpenCommon( p_dec );
310 311 312 313 314 315 316 317 318
    if( ret == VLC_SUCCESS )
        p_dec->pf_packetize = SendFrame;
    return ret;
}

/**
 * Common deinitialization
 */
static void CloseCommon( vlc_object_t *p_this )
319
{
320 321
    decoder_t *p_dec = (decoder_t*)p_this;
    free( p_dec->p_sys );
322
}