You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

306 lines
9.3 KiB

/*****************************************************************************
* dv.c: a decoder for DV video
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: dv.c,v 1.2 2002/08/12 09:34:15 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
#include <libdv/dv_types.h>
#include <libdv/dv.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int RunDecoder ( decoder_fifo_t * );
static int OpenDecoder ( vlc_object_t * );
static u32 GetFourCC ( dv_sample_t );
static pes_packet_t *GetFirstPES( decoder_fifo_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("DV video decoder") );
set_capability( "decoder", 70 );
set_callbacks( OpenDecoder, NULL );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
* The fourcc format for DV is "dvsd"
*****************************************************************************/
static int OpenDecoder ( vlc_object_t *p_this )
{
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( p_fifo->i_fourcc != VLC_FOURCC('d','v','s','d') )
{
return VLC_EGENERIC;
}
p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
}
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
static int RunDecoder ( decoder_fifo_t *p_fifo )
{
u8 *p_buffer;
int i_data = 120000;
int i_aspect;
bit_stream_t bit_stream;
dv_decoder_t * p_decoder;
vout_thread_t * p_vout;
p_buffer = malloc( i_data );
if( !p_buffer )
{
msg_Err( p_fifo, "out of memory" );
p_fifo->b_error = 1;
DecoderError( p_fifo );
return -1;
}
p_decoder = dv_decoder_new( TRUE, FALSE, FALSE );
if( !p_decoder )
{
msg_Err( p_fifo, "cannot create DV decoder" );
free( p_buffer );
p_fifo->b_error = 1;
DecoderError( p_fifo );
return -1;
}
InitBitstream( &bit_stream, p_fifo, NULL, NULL );
/* Fill the buffer */
GetChunk( &bit_stream, p_buffer, i_data );
while( !p_fifo->b_die && !p_fifo->b_error )
{
/* Parsing the beginning of the stream */
if( dv_parse_header( p_decoder, p_buffer ) < 0 )
{
fprintf(stderr, "parse error\n");
p_fifo->b_error = 1;
break;
}
if( dv_format_wide( p_decoder ) )
{
msg_Dbg( p_fifo, "aspect is 4:3" );
i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
}
else if( dv_format_normal( p_decoder ) )
{
msg_Dbg( p_fifo, "aspect is 16:9" );
i_aspect = VOUT_ASPECT_FACTOR * 4/3;//16 / 9;
}
else
{
msg_Dbg( p_fifo, "aspect is square pixels" );
i_aspect = VOUT_ASPECT_FACTOR
* p_decoder->width / p_decoder->height;
}
if( p_decoder->frame_size <= i_data )
{
/* XXX: what to do? */
i_data = p_decoder->frame_size;
}
else
{
p_buffer = realloc( p_buffer, p_decoder->frame_size );
}
/* Don't trust the sucker */
//p_decoder->quality = p_decoder->video->quality;
p_decoder->quality = DV_QUALITY_BEST;
p_decoder->prev_frame_decoded = 0;
/* Spawn a video output if there is none. First we look amongst our
* children, then we look for any other vout that might be available */
p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_CHILD );
if( !p_vout )
{
p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_ANYWHERE );
}
if( p_vout )
{
if( p_vout->render.i_width != p_decoder->width
|| p_vout->render.i_height != p_decoder->height
|| p_vout->render.i_chroma != GetFourCC( p_decoder->sampling )
|| p_vout->render.i_aspect != i_aspect )
{
/* We are not interested in this format, close this vout */
vlc_object_detach( p_vout );
vlc_object_release( p_vout );
vout_DestroyThread( p_vout );
p_vout = NULL;
}
else
{
/* This video output is cool! Hijack it. */
vlc_object_detach( p_vout );
vlc_object_attach( p_vout, p_fifo );
vlc_object_release( p_vout );
}
}
if( !p_vout )
{
msg_Dbg( p_fifo, "no vout present, spawning one" );
p_vout = vout_CreateThread( p_fifo,
p_decoder->width, p_decoder->height,
GetFourCC( p_decoder->sampling ),
i_aspect );
}
/* Main loop */
while( !p_fifo->b_die && !p_fifo->b_error )
{
mtime_t i_pts = 0;
pes_packet_t *p_pes;
GetChunk( &bit_stream, p_buffer + i_data,
p_decoder->frame_size - i_data );
i_data = p_decoder->frame_size;
p_pes = GetFirstPES( p_fifo );
if( p_pes )
{
/* Don't trust the sucker */
//i_pts = p_pes->i_pts + DEFAULT_PTS_DELAY;
i_pts = mdate() + DEFAULT_PTS_DELAY;
}
if( p_fifo->b_die || p_fifo->b_error )
{
break;
}
if( dv_parse_header( p_decoder, p_buffer ) > 0 )
{
fprintf(stderr, "size changed\n");
}
if( p_vout && ( !p_decoder->prev_frame_decoded
|| dv_frame_changed( p_decoder ) ) )
{
picture_t *p_pic;
u8 *pixels[3];
int pitches[3], i;
while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
{
if( p_fifo->b_die || p_fifo->b_error )
{
break;
}
msleep( VOUT_OUTMEM_SLEEP );
}
if( !p_pic )
{
break;
}
for( i = 0 ; i < p_pic->i_planes ; i++ )
{
pixels[i] = p_pic->p[i].p_pixels;
pitches[i] = p_pic->p[i].i_pitch;
}
dv_decode_full_frame( p_decoder, p_buffer,
e_dv_color_yuv, pixels, pitches );
p_decoder->prev_frame_decoded = 1;
vout_DatePicture( p_vout, p_pic, i_pts );
vout_DisplayPicture( p_vout, p_pic );
}
i_data = 0;
}
if( p_vout )
{
vout_DestroyThread( p_vout );
}
}
free( p_buffer );
if( p_fifo->b_error )
{
DecoderError( p_fifo );
return -1;
}
return 0;
}
static u32 GetFourCC( dv_sample_t x )
{
switch( x )
{
case e_dv_sample_411: return VLC_FOURCC('Y','U','Y','2');
case e_dv_sample_420: return VLC_FOURCC('Y','U','Y','2');
case e_dv_sample_422: return VLC_FOURCC('Y','U','Y','2');
default: return 0;
}
}
static pes_packet_t *GetFirstPES( decoder_fifo_t *p_fifo )
{
pes_packet_t *p_pes;
vlc_mutex_lock( &p_fifo->data_lock );
/* if fifo is empty wait */
while( !p_fifo->p_first )
{
if( p_fifo->b_die )
{
vlc_mutex_unlock( &p_fifo->data_lock );
return NULL;
}
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
p_pes = p_fifo->p_first;
vlc_mutex_unlock( &p_fifo->data_lock );
return p_pes;
}