Commit 35579492 authored by Laurent Aimar's avatar Laurent Aimar

* include/vlc_bits.h: bit stream reader/writer.

 * mpeg4video.c: rework of the mpeg4 video packetizer.
 (not well tested)
parent 7d0dc9c4
......@@ -90,6 +90,7 @@ HEADERS_include = \
include/variables.h \
include/video_output.h \
include/vlc_block.h \
include/vlc_bits.h \
include/vlc_block_helper.h \
include/vlc_codec.h \
include/vlc_common.h \
......
/*****************************************************************************
* bits.h :
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: vlc_bits.h,v 1.1 2003/11/18 20:15:38 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* 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.
*****************************************************************************/
#ifndef _VLC_BITS_H
#define _VLC_BITS_H 1
typedef struct bs_s
{
uint8_t *p_start;
uint8_t *p;
uint8_t *p_end;
int i_left; /* i_count number of available bits */
} bs_t;
static inline void bs_init( bs_t *s, void *p_data, int i_data )
{
s->p_start = p_data;
s->p = p_data;
s->p_end = s->p + i_data;
s->i_left = 8;
}
static inline int bs_pos( bs_t *s )
{
return( 8 * ( s->p - s->p_start ) + 8 - s->i_left );
}
static inline int bs_eof( bs_t *s )
{
return( s->p >= s->p_end ? 1: 0 );
}
static inline uint32_t bs_read( bs_t *s, int i_count )
{
static uint32_t i_mask[33] =
{ 0x00,
0x01, 0x03, 0x07, 0x0f,
0x1f, 0x3f, 0x7f, 0xff,
0x1ff, 0x3ff, 0x7ff, 0xfff,
0x1fff, 0x3fff, 0x7fff, 0xffff,
0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
int i_shr;
uint32_t i_result = 0;
while( i_count > 0 )
{
if( s->p >= s->p_end )
{
break;
}
if( ( i_shr = s->i_left - i_count ) >= 0 )
{
/* more in the buffer than requested */
i_result |= ( *s->p >> i_shr )&i_mask[i_count];
s->i_left -= i_count;
if( s->i_left == 0 )
{
s->p++;
s->i_left = 8;
}
return( i_result );
}
else
{
/* less in the buffer than requested */
i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
i_count -= s->i_left;
s->p++;
s->i_left = 8;
}
}
return( i_result );
}
static inline uint32_t bs_read1( bs_t *s )
{
if( s->p < s->p_end )
{
unsigned int i_result;
s->i_left--;
i_result = ( *s->p >> s->i_left )&0x01;
if( s->i_left == 0 )
{
s->p++;
s->i_left = 8;
}
return i_result;
}
return 0;
}
static inline uint32_t bs_show( bs_t *s, int i_count )
{
bs_t s_tmp = *s;
return bs_read( &s_tmp, i_count );
}
static inline void bs_skip( bs_t *s, int i_count )
{
s->i_left -= i_count;
while( s->i_left <= 0 )
{
s->p++;
s->i_left += 8;
}
}
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
{
while( i_count > 0 )
{
if( s->p >= s->p_end )
{
break;
}
i_count--;
if( ( i_bits >> i_count )&0x01 )
{
*s->p |= 1 << ( s->i_left - 1 );
}
else
{
*s->p &= ~( 1 << ( s->i_left - 1 ) );
}
s->i_left--;
if( s->i_left == 0 )
{
s->p++;
s->i_left = 8;
}
}
}
static inline void bs_align( bs_t *s )
{
if( s->i_left != 8 )
{
s->i_left = 8;
s->p++;
}
}
static inline void bs_align_0( bs_t *s )
{
if( s->i_left != 8 )
{
bs_write( s, s->i_left, 0 );
}
}
static inline void bs_align_1( bs_t *s )
{
while( s->i_left != 8 )
{
bs_write( s, 1, 1 );
}
}
#endif
......@@ -2,7 +2,7 @@
* mpeg4video.c: mpeg 4 video packetizer
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: mpeg4video.c,v 1.15 2003/11/17 18:48:08 gbazin Exp $
* $Id: mpeg4video.c,v 1.16 2003/11/18 20:15:38 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org>
......@@ -26,36 +26,49 @@
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include <vlc/input.h>
#include <vlc/sout.h>
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include "codecs.h"
#include "vlc_bits.h"
/*****************************************************************************
* decoder_sys_t : decoder descriptor
* Module descriptor
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
vlc_module_begin();
set_description( _("MPEG4 Video packetizer") );
set_capability( "packetizer", 50 );
set_callbacks( Open, Close );
vlc_module_end();
/****************************************************************************
* Local prototypes
****************************************************************************/
static block_t *Packetize( decoder_t *, block_t ** );
struct decoder_sys_t
{
/*
* Common properties
*/
mtime_t i_pts;
};
mtime_t i_dts;
/****************************************************************************
* Local prototypes
****************************************************************************/
static int OpenPacketizer ( vlc_object_t * );
static void ClosePacketizer( vlc_object_t * );
static block_t *PacketizeBlock( decoder_t *, block_t ** );
vlc_bool_t b_vop;
int i_buffer;
int i_buffer_size;
uint8_t *p_buffer;
};
static int m4v_FindVol( decoder_t *p_dec, block_t *p_block );
static int m4v_FindStartCode( uint8_t **pp_start, uint8_t *p_end );
static int m4v_VOLParse( es_format_t *fmt, uint8_t *p_vol, int i_vol );
#define VIDEO_OBJECT_MASK 0x01f
#define VIDEO_OBJECT_LAYER_MASK 0x00f
......@@ -78,23 +91,14 @@ static int m4v_FindVol( decoder_t *p_dec, block_t *p_block );
#define TEXTURE_SNR_LAYER_START_CODE 0x1c0
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("MPEG4 Video packetizer") );
set_capability( "packetizer", 50 );
set_callbacks( OpenPacketizer, ClosePacketizer );
vlc_module_end();
/*****************************************************************************
* OpenPacketizer: probe the packetizer and return score
* Open: probe the packetizer and return score
*****************************************************************************/
static int OpenPacketizer( vlc_object_t *p_this )
static int Open( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*)p_this;
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
switch( p_dec->p_fifo->i_fourcc )
switch( p_dec->fmt_in.i_codec )
{
case VLC_FOURCC( 'm', '4', 's', '2'):
case VLC_FOURCC( 'M', '4', 'S', '2'):
......@@ -116,12 +120,16 @@ static int OpenPacketizer( vlc_object_t *p_this )
}
/* Allocate the memory needed to store the decoder's structure */
if( ( p_dec->p_sys = p_sys =
(decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL )
{
msg_Err( p_dec, "out of memory" );
return VLC_EGENERIC;
}
p_sys->i_pts = 0;
p_sys->b_vop = VLC_FALSE;
p_sys->i_buffer = 0;
p_sys->i_buffer_size = 10000;
p_sys->p_buffer = malloc( p_sys->i_buffer_size );
/* Setup properties */
p_dec->fmt_out = p_dec->fmt_in;
......@@ -136,6 +144,8 @@ static int OpenPacketizer( vlc_object_t *p_this )
p_dec->fmt_in.i_extra );
msg_Dbg( p_dec, "opening with vol size:%d", p_dec->fmt_in.i_extra );
m4v_VOLParse( &p_dec->fmt_out,
p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
}
else
{
......@@ -145,135 +155,292 @@ static int OpenPacketizer( vlc_object_t *p_this )
}
/* Set callback */
p_dec->pf_packetize = PacketizeBlock;
p_dec->pf_packetize = Packetize;
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: clean up the packetizer
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*)p_this;
free( p_dec->p_sys );
}
/****************************************************************************
* PacketizeBlock: the whole thing
* Packetize: the whole thing
****************************************************************************/
static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_chain_out = NULL;
block_t *p_block;
uint8_t *p_vol = NULL;
uint8_t *p_start;
if( !pp_block || !*pp_block ) return NULL;
p_block = *pp_block;
if( !p_dec->fmt_out.i_extra )
/* Append data */
if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
{
m4v_FindVol( p_dec, p_block );
p_sys->i_buffer_size += p_block->i_buffer + 1024;
p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
}
memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer,
p_block->i_buffer );
p_sys->i_buffer += p_block->i_buffer;
/* Drop blocks until we have a VOL */
if( !p_dec->fmt_out.i_extra )
if( p_sys->i_buffer > 10*1000000 )
{
block_Release( p_block );
return NULL;
msg_Err( p_dec, "mmh reseting context" );
p_sys->i_buffer = 0;
}
/* TODO: Date management */
p_block->i_length = 1000000 / 25;
/* Search vop */
p_start = &p_sys->p_buffer[p_sys->i_buffer - p_block->i_buffer - 4];
if( p_start < p_sys->p_buffer )
{
p_start = p_sys->p_buffer;
}
for( ;; )
{
if( m4v_FindStartCode( &p_start, &p_sys->p_buffer[p_sys->i_buffer] ) )
{
block_Release( p_block );
*pp_block = NULL;
return p_chain_out;
}
/* fprintf( stderr, "start code=0x1%2.2x\n", p_start[3] ); */
if( p_vol )
{
/* Copy the complete VOL */
p_dec->fmt_out.i_extra = p_start - p_vol;
p_dec->fmt_out.p_extra = malloc( p_dec->fmt_out.i_extra );
memcpy( p_dec->fmt_out.p_extra, p_vol, p_dec->fmt_out.i_extra );
m4v_VOLParse( &p_dec->fmt_out,
p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
*pp_block = NULL;
return p_block;
p_vol = NULL;
}
if( p_sys->b_vop )
{
/* Output the complete VOP we have */
int i_out = p_start - p_sys->p_buffer;
block_t *p_out = block_New( p_dec, i_out );
/* extract data */
memcpy( p_out->p_buffer, p_sys->p_buffer, i_out );
if( i_out < p_sys->i_buffer )
{
memmove( p_sys->p_buffer, &p_sys->p_buffer[i_out],
p_sys->i_buffer - i_out );
}
p_sys->i_buffer -= i_out;
p_start -= i_out;
/* FIXME do proper dts/pts */
p_out->i_pts = p_sys->i_pts;
p_out->i_dts = p_sys->i_dts;
/* FIXME doesn't work when there is multiple VOP in one block */
if( p_block->i_dts > p_sys->i_dts )
{
p_out->i_length = p_block->i_dts - p_sys->i_dts;
}
if( p_dec->fmt_out.i_extra > 0 )
{
block_ChainAppend( &p_chain_out, p_out );
}
else
{
msg_Warn( p_dec, "waiting for VOL" );
block_Release( p_out );
}
#if 0
fprintf( stderr, "pts=%lld dts=%lld length=%lldms\n",
p_out->i_pts, p_out->i_dts,
p_out->i_length / 1000 );
#endif
p_sys->b_vop = VLC_FALSE;
}
if( p_start[3] >= 0x20 && p_start[3] <= 0x2f )
{
/* Start of the VOL */
p_vol = p_start;
}
else if( p_start[3] == 0xb6 )
{
p_sys->b_vop = VLC_TRUE;
p_sys->i_pts = p_block->i_pts;
p_sys->i_dts = p_block->i_dts;
}
p_start += 4; /* Next */
}
}
/****************************************************************************
* m4v_FindStartCode
****************************************************************************/
static int m4v_FindStartCode( uint8_t **pp_data, uint8_t *p_end )
static int m4v_FindStartCode( uint8_t **pp_start, uint8_t *p_end )
{
for( ; *pp_data < p_end - 4; (*pp_data)++ )
uint8_t *p = *pp_start;
for( p = *pp_start; p < p_end - 4; p++ )
{
if( (*pp_data)[0] == 0 && (*pp_data)[1] == 0 && (*pp_data)[2] == 1 )
if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
{
return 0;
*pp_start = p;
return VLC_SUCCESS;
}
}
return -1;
*pp_start = p_end;
return VLC_EGENERIC;
}
static int m4v_FindVol( decoder_t *p_dec, block_t *p_block )
/* look at ffmpeg av_log2 ;) */
static int vlc_log2( unsigned int v )
{
uint8_t *p_vol_begin, *p_vol_end, *p_end;
int n = 0;
static const int vlc_log2_table[16] =
{
0,0,1,1,2,2,2,2, 3,3,3,3,3,3,3,3
};
/* search if p_block contains with a vol */
p_vol_begin = p_block->p_buffer;
p_vol_end = NULL;
p_end = p_block->p_buffer + p_block->i_buffer;
if( v&0xffff0000 )
{
v >>= 16;
n += 16;
}
if( v&0xff00 )
{
v >>= 8;
n += 8;
}
if( v&0xf0 )
{
v >>= 4;
n += 4;
}
n += vlc_log2_table[v];
return n;
}
/* m4v_VOLParse:
* TODO:
* - support aspect ratio
*/
static int m4v_VOLParse( es_format_t *fmt, uint8_t *p_vol, int i_vol )
{
bs_t s;
int i_vo_type;
int i_vo_ver_id;
int i_ar;
int i_shape;
int i_time_increment_resolution;
for( ;; )
{
if( m4v_FindStartCode( &p_vol_begin, p_end ) )
if( p_vol[0] == 0x00 && p_vol[1] == 0x00 &&
p_vol[2] == 0x01 &&
p_vol[3] >= 0x20 && p_vol[3] <= 0x2f )
{
break;
}
msg_Dbg( p_dec, "starcode 0x%2.2x%2.2x%2.2x%2.2x",
p_vol_begin[0], p_vol_begin[1],
p_vol_begin[2], p_vol_begin[3] );
if( ( p_vol_begin[3] & ~VIDEO_OBJECT_MASK ) ==
( VIDEO_OBJECT_START_CODE&0xff ) )
p_vol++;
i_vol--;
if( i_vol <= 4 )
{
p_vol_end = p_vol_begin + 4;
if( m4v_FindStartCode( &p_vol_end, p_end ) )
{
p_vol_begin++;
continue;
}
if( ( p_vol_end[3] & ~VIDEO_OBJECT_LAYER_MASK ) ==
( VIDEO_OBJECT_LAYER_START_CODE&0xff ) )
{
p_vol_end += 4;
if( m4v_FindStartCode( &p_vol_end, p_end ) )
{
p_vol_end = p_end;
}
}
else
{
p_vol_begin++;
continue;
}
return VLC_EGENERIC;
}
else if( ( p_vol_begin[3] & ~VIDEO_OBJECT_LAYER_MASK ) ==
( VIDEO_OBJECT_LAYER_START_CODE&0xff) )
}
/* parse the vol */
bs_init( &s, &p_vol[4], i_vol - 4 );
bs_skip( &s, 1 ); /* random access */
i_vo_type = bs_read( &s, 8 );
if( bs_read1( &s ) )
{
i_vo_ver_id = bs_read( &s, 4 );
bs_skip( &s, 3 );
}
else
{
i_vo_ver_id = 1;
}
i_ar = bs_read( &s, 4 );
if( i_ar == 0xf )
{
int i_ar_width = bs_read( &s, 8 );
int i_ar_height= bs_read( &s, 8 );
}
if( bs_read1( &s ) )
{
/* vol control parameter */
int i_chroma_format = bs_read( &s, 2 );
int i_low_delay = bs_read1( &s );
if( bs_read1( &s ) )
{
p_vol_end = p_vol_begin + 4;
if( m4v_FindStartCode( &p_vol_end, p_end ) )
{
p_vol_end = p_end;
}
bs_skip( &s, 16 );
bs_skip( &s, 16 );
bs_skip( &s, 16 );
bs_skip( &s, 3 );
bs_skip( &s, 11 );
bs_skip( &s, 1 );
bs_skip( &s, 16 );
}
}
/* shape 0->RECT, 1->BIN, 2->BIN_ONLY, 3->GRAY */
i_shape = bs_read( &s, 2 );
if( i_shape == 3 && i_vo_ver_id != 1 )
{
bs_skip( &s, 4 );
}
if( p_vol_end != NULL && p_vol_begin < p_vol_end )
{
p_dec->fmt_out.i_extra = p_vol_end - p_vol_begin;
msg_Dbg( p_dec, "Found VOL" );
if( !bs_read1( &s ) )
{
/* marker */
return VLC_EGENERIC;
}
i_time_increment_resolution = bs_read( &s, 16 );
if( !bs_read1( &s ) )
{
/* marker */
return VLC_EGENERIC;
}
p_dec->fmt_out.p_extra = malloc( p_dec->fmt_out.i_extra );
memcpy( p_dec->fmt_out.p_extra, p_vol_begin,
p_dec->fmt_out.i_extra );
return VLC_SUCCESS;
}
else
if( bs_read1( &s ) )
{
int i_time_increment_bits = vlc_log2( i_time_increment_resolution - 1 ) + 1;
if( i_time_increment_bits < 1 )
{
p_vol_begin++;
i_time_increment_bits = 1;
}
bs_skip( &s, i_time_increment_bits );
}
if( i_shape == 0 )
{
bs_skip( &s, 1 );
fmt->video.i_width = bs_read( &s, 13 );
bs_skip( &s, 1 );
fmt->video.i_height= bs_read( &s, 13 );
bs_skip( &s, 1 );
}
return VLC_SUCCESS;
}
/*****************************************************************************
* ClosePacketizer: clean up the packetizer
*****************************************************************************/
static void ClosePacketizer( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*)p_this;
free( p_dec->p_sys );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment