cdg.c 6.23 KB
Newer Older
Laurent Aimar's avatar
Laurent Aimar committed
1 2 3 4
/*****************************************************************************
 * cdg.c : cdg file demux module for vlc
 *****************************************************************************
 * Copyright (C) 2007 Laurent Aimar
Rafaël Carré's avatar
Rafaël Carré committed
5
 * $Id$
Laurent Aimar's avatar
Laurent Aimar committed
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
Laurent Aimar's avatar
Laurent Aimar committed
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.
Laurent Aimar's avatar
Laurent Aimar committed
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.
Laurent Aimar's avatar
Laurent Aimar committed
22 23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
Laurent Aimar's avatar
Laurent Aimar committed
34 35 36 37 38 39 40 41
#include <vlc_demux.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

42 43 44 45 46 47
vlc_module_begin ()
    set_description( N_("CDG demuxer") )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_capability( "demux", 3 )
    set_callbacks( Open, Close )
48
    add_shortcut( "cdg", "subtitle" )
49
vlc_module_end ()
Laurent Aimar's avatar
Laurent Aimar committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int Demux  ( demux_t * );
static int Control( demux_t *, int i_query, va_list args );

struct demux_sys_t
{
    es_format_t     fmt;
    es_out_id_t     *p_es;

    date_t          pts;
};

#define CDG_FRAME_SIZE (96)
#define CDG_FRAME_RATE (75)

/*****************************************************************************
 * Open: check file and initializes structures
 *****************************************************************************/
static int Open( vlc_object_t * p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;

    /* Identify cdg file by extension, as there is no simple way to
     * detect it */
78
    if( !demux_IsPathExtension( p_demux, ".cdg" ) && !demux_IsForced( p_demux, "cdg" ) )
Laurent Aimar's avatar
Laurent Aimar committed
79 80 81 82 83 84 85 86 87 88
        return VLC_EGENERIC;

    /* CDG file size has to be multiple of CDG_FRAME_SIZE (it works even
     * if size is unknown ie 0) */
//    if( (stream_Size( p_demux->s ) % CDG_FRAME_SIZE) != 0 )
//    {
//        msg_Err( p_demux, "Reject CDG file based on its size" );
//        return VLC_EGENERIC;
//    }

89 90 91 92
    p_sys = malloc( sizeof( demux_sys_t ) );
    if( unlikely(p_sys == NULL) )
        return VLC_ENOMEM;

Laurent Aimar's avatar
Laurent Aimar committed
93 94
    p_demux->pf_demux   = Demux;
    p_demux->pf_control = Control;
95
    p_demux->p_sys      = p_sys;
Laurent Aimar's avatar
Laurent Aimar committed
96 97

    /* */
98
    es_format_Init( &p_sys->fmt, VIDEO_ES, VLC_CODEC_CDG );
Laurent Aimar's avatar
Laurent Aimar committed
99 100
    p_sys->fmt.video.i_width  = 300-2*6;
    p_sys->fmt.video.i_height = 216-2*12 ;
101 102
    p_sys->fmt.video.i_visible_width = p_sys->fmt.video.i_width;
    p_sys->fmt.video.i_visible_height = p_sys->fmt.video.i_height;
Laurent Aimar's avatar
Laurent Aimar committed
103 104 105 106 107

    p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );

    /* There is CDG_FRAME_RATE frames per second */
    date_Init( &p_sys->pts, CDG_FRAME_RATE, 1 );
108
    date_Set( &p_sys->pts, 0 );
Laurent Aimar's avatar
Laurent Aimar committed
109 110 111 112 113 114 115 116 117 118 119 120 121

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Demux: read packet and send them to decoders
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    block_t     *p_block;
Zhao Zhili's avatar
Zhao Zhili committed
122 123 124 125
    mtime_t     i_date;
    mtime_t     i_delta;

    i_delta = INT64_C(1000000) / CDG_FRAME_RATE;
Laurent Aimar's avatar
Laurent Aimar committed
126

127
    p_block = vlc_stream_Block( p_demux->s, CDG_FRAME_SIZE );
Laurent Aimar's avatar
Laurent Aimar committed
128 129 130 131 132 133
    if( p_block == NULL )
    {
        msg_Dbg( p_demux, "cannot read data, eof" );
        return 0;
    }

134
    i_date = vlc_stream_Tell( p_demux->s ) / CDG_FRAME_SIZE * i_delta;
Zhao Zhili's avatar
Zhao Zhili committed
135 136 137 138 139 140 141 142 143 144
    if( i_date >= date_Get( &p_sys->pts ) + i_delta )
    {
        p_block->i_dts = p_block->i_pts = i_date;
        date_Set( &p_sys->pts, i_date );
    }
    else
    {
        p_block->i_dts = i_date;
        p_block->i_pts = date_Get( &p_sys->pts );
    }
Laurent Aimar's avatar
Laurent Aimar committed
145

146
    es_out_SetPCR( p_demux->out, p_block->i_pts );
Laurent Aimar's avatar
Laurent Aimar committed
147 148

    es_out_Send( p_demux->out, p_sys->p_es, p_block );
149

Laurent Aimar's avatar
Laurent Aimar committed
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    return 1;
}

/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close ( vlc_object_t * p_this )
{
    demux_t *p_demux = (demux_t *)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;

    free( p_sys );
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
169
    uint64_t i_old_offset = vlc_stream_Tell( p_demux->s );
170 171 172 173
    int i_ret = demux_vaControlHelper( p_demux->s, 0, -1,
                                       8*CDG_FRAME_SIZE*CDG_FRAME_RATE, CDG_FRAME_SIZE,
                                       i_query, args );
    if( !i_ret && ( i_query == DEMUX_SET_POSITION || i_query == DEMUX_SET_TIME ) )
Zhao Zhili's avatar
Zhao Zhili committed
174
    {
175
        date_Set( &p_demux->p_sys->pts,
176
                  vlc_stream_Tell( p_demux->s ) / CDG_FRAME_SIZE *
177
                    INT64_C(1000000) / CDG_FRAME_RATE );
178 179
        if ( i_old_offset > vlc_stream_Tell( p_demux->s ) )
            i_ret = vlc_stream_Seek( p_demux->s, 0 );
Zhao Zhili's avatar
Zhao Zhili committed
180
        else
181
            i_ret = vlc_stream_Seek( p_demux->s, i_old_offset );
Zhao Zhili's avatar
Zhao Zhili committed
182
    }
183 184

    return i_ret;
Laurent Aimar's avatar
Laurent Aimar committed
185 186
}