@ -2,6 +2,12 @@
* DV decoder
* Copyright ( c ) 2002 Fabrice Bellard .
*
* DV encoder
* Copyright ( c ) 2003 Roman Shaposhnik .
*
* Many thanks to Dan Dennedy < dan @ dennedy . org > for providing wealth
* of DV technical info .
*
* This library 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
@ -19,7 +25,7 @@
/**
* @ file dv . c
* DV decoder .
* DV codec .
*/
# include "avcodec.h"
# include "dsputil.h"
@ -72,7 +78,7 @@ static void dv_build_unquantize_tables(DVVideoDecodeContext *s)
}
}
static int dvvideo_decode_ init ( AVCodecContext * avctx )
static int dvvideo_init ( AVCodecContext * avctx )
{
DVVideoDecodeContext * s = avctx - > priv_data ;
MpegEncContext s2 ;
@ -140,6 +146,10 @@ static int dvvideo_decode_init(AVCodecContext *avctx)
/* XXX: do it only for constant case */
dv_build_unquantize_tables ( s ) ;
/* FIXME: I really don't think this should be here */
if ( dv_codec_profile ( avctx ) )
avctx - > pix_fmt = dv_codec_profile ( avctx ) - > pix_fmt ;
return 0 ;
}
@ -368,6 +378,9 @@ static inline void dv_decode_video_segment(DVVideoDecodeContext *s,
mb - > pos = 0 ;
mb - > partial_bit_count = 0 ;
# ifdef VLC_DEBUG
printf ( " MB block: %d, %d " , mb_index , j ) ;
# endif
dv_decode_ac ( s , mb , block , last_index ) ;
/* write the remaining bits in a new buffer only if the
@ -391,7 +404,7 @@ static inline void dv_decode_video_segment(DVVideoDecodeContext *s,
/* pass 2 : we can do it just after */
# ifdef VLC_DEBUG
printf ( " ***pass 2 size=%d \n " , mb_bit_count ) ;
printf ( " ***pass 2 size=%d MB#=%d \n " , mb_bit_count , mb_index ) ;
# endif
block = block1 ;
mb = mb1 ;
@ -501,6 +514,317 @@ static inline void dv_decode_video_segment(DVVideoDecodeContext *s,
}
}
/* Converts run and level (where level != 0) pair into vlc, returning bit size */
static inline int dv_rl2vlc ( int run , int l , uint32_t * vlc )
{
int sign = l > > 8 ;
int level = ( l ^ sign ) - sign ;
int size ;
sign = ( sign & 1 ) ;
if ( run < 15 & & level < 23 & & dv_vlc_codes [ run ] [ level ] ! = - 1 ) {
* vlc = ( dv_vlc_bits [ dv_vlc_codes [ run ] [ level ] ] < < 1 ) | sign ;
size = dv_vlc_len [ dv_vlc_codes [ run ] [ level ] ] + 1 ;
}
else {
if ( level < 23 ) {
* vlc = ( dv_vlc_bits [ dv_vlc_codes [ 0 ] [ level ] ] < < 1 ) | sign ;
size = dv_vlc_len [ dv_vlc_codes [ 0 ] [ level ] ] + 1 ;
} else {
* vlc = 0xfe00 | ( level < < 1 ) | sign ;
size = 16 ;
}
switch ( run ) {
case 0 :
break ;
case 1 :
case 2 :
* vlc | = ( ( 0x7ce | ( run - 1 ) ) < < size ) ;
size + = 11 ;
break ;
case 3 :
case 4 :
case 5 :
case 6 :
* vlc | = ( ( 0xfac | ( run - 3 ) ) < < size ) ;
size + = 12 ;
break ;
default :
* vlc | = ( ( 0x1f80 | ( run - 1 ) ) < < size ) ;
size + = 13 ;
break ;
}
}
return size ;
}
typedef struct EncBlockInfo {
int qno ;
int cno ;
int dct_mode ;
int block_size ;
DCTELEM * mb ;
PutBitContext pb ;
} EncBlockInfo ;
static inline int dv_bits_left ( EncBlockInfo * bi )
{
return ( bi - > block_size - get_bit_count ( & bi - > pb ) ) ;
}
static inline void dv_encode_ac ( EncBlockInfo * bi , PutBitContext * heap )
{
int i , level , size , run = 0 ;
uint32_t vlc ;
PutBitContext * cpb = & bi - > pb ;
for ( i = 1 ; i < 64 ; i + + ) {
level = bi - > mb [ ff_zigzag_direct [ i ] ] /
( 1 < < ( dv_quant_shifts [ bi - > qno + dv_quant_offset [ bi - > cno ] ]
[ dv_88_areas [ ff_zigzag_direct [ i ] ] ] + 4 + ( bi - > cno = = 3 ) ) ) ;
if ( level ! = 0 ) {
size = dv_rl2vlc ( run , level , & vlc ) ;
put_vlc :
# ifdef VLC_DEBUG
printf ( " %3d:%3d " , run , level ) ;
# endif
if ( cpb = = & bi - > pb & & size > dv_bits_left ( bi ) ) {
size - = dv_bits_left ( bi ) ;
put_bits ( cpb , dv_bits_left ( bi ) , vlc > > size ) ;
vlc = vlc & ( ( 1 < < size ) - 1 ) ;
cpb = heap ;
}
put_bits ( cpb , size , vlc ) ;
run = 0 ;
} else
run + + ;
}
if ( i = = 64 ) {
size = 4 ; vlc = 6 ; /* End Of Block stamp */
goto put_vlc ;
}
}
static inline void dv_redistr_bits ( EncBlockInfo * bi , int count , uint8_t * extra_data , int extra_bits , PutBitContext * heap )
{
int i ;
GetBitContext gb ;
init_get_bits ( & gb , extra_data , extra_bits ) ;
for ( i = 0 ; i < count ; i + + ) {
int bits_left = dv_bits_left ( bi ) ;
# ifdef VLC_DEBUG
if ( bits_left )
printf ( " ------------> inserting %d bytes in %d:%d \n " , bits_left , i / 6 , i % 6 ) ;
# endif
if ( bits_left > extra_bits ) {
bit_copy ( & bi - > pb , & gb , extra_bits ) ;
extra_bits = 0 ;
break ;
} else
bit_copy ( & bi - > pb , & gb , bits_left ) ;
extra_bits - = bits_left ;
bi + + ;
}
if ( extra_bits > 0 & & heap )
bit_copy ( heap , & gb , extra_bits ) ;
}
static inline void dv_set_class_number ( EncBlockInfo * bi , int j )
{
int i , max_ac = 0 ;
for ( i = 1 ; i < 64 ; i + + ) {
int ac = abs ( bi - > mb [ ff_zigzag_direct [ i ] ] ) / 4 ;
if ( max_ac < ac )
max_ac = ac ;
}
if ( max_ac < 12 )
bi - > cno = j ;
else if ( max_ac < 24 )
bi - > cno = j + 1 ;
else if ( max_ac < 36 )
bi - > cno = j + 2 ;
else
bi - > cno = j + 3 ;
if ( bi - > cno > 3 )
bi - > cno = 3 ;
}
/*
* This is a very rough initial implementaion . The performance is
* horrible and some features are missing , mainly 2 - 4 - 8 DCT encoding .
* The weighting is missing as well , but it ' s missing from the decoding
* step also - - so at least we ' re on the same page with decoder ; - )
*/
static inline void dv_encode_video_segment ( DVVideoDecodeContext * s ,
uint8_t * dif ,
const uint16_t * mb_pos_ptr )
{
int mb_index , i , j , v ;
int mb_x , mb_y , c_offset , linesize ;
uint8_t * y_ptr ;
uint8_t * data ;
int do_edge_wrap ;
DCTELEM * block ;
EncBlockInfo enc_blks [ 5 * 6 ] ;
EncBlockInfo * enc_blk ;
int free_vs_bits ;
int extra_bits ;
PutBitContext extra_vs ;
uint8_t extra_vs_data [ 5 * 6 * 128 ] ;
uint8_t extra_mb_data [ 6 * 128 ] ;
int QNO = 15 ;
/* Stage 1 -- doing DCT on 5 MBs */
block = & s - > block [ 0 ] [ 0 ] ;
for ( mb_index = 0 ; mb_index < 5 ; mb_index + + ) {
v = * mb_pos_ptr + + ;
mb_x = v & 0xff ;
mb_y = v > > 8 ;
y_ptr = s - > picture . data [ 0 ] + ( mb_y * s - > picture . linesize [ 0 ] * 8 ) + ( mb_x * 8 ) ;
c_offset = ( s - > sys - > pix_fmt = = PIX_FMT_YUV411P ) ?
( ( mb_y * s - > picture . linesize [ 1 ] * 8 ) + ( ( mb_x > > 2 ) * 8 ) ) :
( ( ( mb_y > > 1 ) * s - > picture . linesize [ 1 ] * 8 ) + ( ( mb_x > > 1 ) * 8 ) ) ;
do_edge_wrap = 0 ;
for ( j = 0 ; j < 6 ; j + + ) {
if ( j < 4 ) { /* Four Y blocks */
/* NOTE: at end of line, the macroblock is handled as 420 */
if ( s - > sys - > pix_fmt = = PIX_FMT_YUV411P & & mb_x < ( 704 / 8 ) ) {
data = y_ptr + ( j * 8 ) ;
} else {
data = y_ptr + ( ( j & 1 ) * 8 ) + ( ( j > > 1 ) * 8 * s - > picture . linesize [ 0 ] ) ;
}
linesize = s - > picture . linesize [ 0 ] ;
} else { /* Cr and Cb blocks */
/* don't ask Fabrice why they inverted Cb and Cr ! */
data = s - > picture . data [ 6 - j ] + c_offset ;
linesize = s - > picture . linesize [ 6 - j ] ;
if ( s - > sys - > pix_fmt = = PIX_FMT_YUV411P & & mb_x > = ( 704 / 8 ) )
do_edge_wrap = 1 ;
}
/* Everything is set up -- now just copy data -> DCT block */
if ( do_edge_wrap ) { /* Edge wrap copy: 4x16 -> 8x8 */
uint8_t * d ;
DCTELEM * b = block ;
for ( i = 0 ; i < 8 ; i + + ) {
d = data + 8 * linesize ;
b [ 0 ] = data [ 0 ] ; b [ 1 ] = data [ 1 ] ; b [ 2 ] = data [ 2 ] ; b [ 3 ] = data [ 3 ] ;
b [ 4 ] = d [ 0 ] ; b [ 5 ] = d [ 1 ] ; b [ 6 ] = d [ 2 ] ; b [ 7 ] = d [ 3 ] ;
data + = linesize ;
b + = 8 ;
}
} else { /* Simple copy: 8x8 -> 8x8 */
s - > get_pixels ( block , data , linesize ) ;
}
s - > fdct ( block ) ;
block + = 64 ;
}
}
/* Stage 2 -- setup for encoding phase */
enc_blk = & enc_blks [ 0 ] ;
block = & s - > block [ 0 ] [ 0 ] ;
for ( i = 0 ; i < 5 ; i + + ) {
for ( j = 0 ; j < 6 ; j + + ) {
enc_blk - > mb = block ;
enc_blk - > dct_mode = 0 ;
enc_blk - > block_size = block_sizes [ j ] ;
dv_set_class_number ( enc_blk , j / 4 * ( j % 2 ) ) ;
block + = 64 ;
enc_blk + + ;
}
}
/* Stage 3 -- encoding by trial-and-error */
encode_vs :
enc_blk = & enc_blks [ 0 ] ;
for ( i = 0 ; i < 5 ; i + + ) {
uint8_t * p = dif + i * 80 + 4 ;
for ( j = 0 ; j < 6 ; j + + ) {
enc_blk - > qno = QNO ;
init_put_bits ( & enc_blk - > pb , p , block_sizes [ j ] / 8 , NULL , NULL ) ;
enc_blk + + ;
p + = block_sizes [ j ] / 8 ;
}
}
init_put_bits ( & extra_vs , extra_vs_data , sizeof ( extra_vs_data ) , NULL , NULL ) ;
free_vs_bits = 0 ;
enc_blk = & enc_blks [ 0 ] ;
for ( i = 0 ; i < 5 ; i + + ) {
PutBitContext extra_mb ;
EncBlockInfo * enc_blk2 = enc_blk ;
int free_mb_bits = 0 ;
init_put_bits ( & extra_mb , extra_mb_data , sizeof ( extra_mb_data ) , NULL , NULL ) ;
dif [ i * 80 + 3 ] = enc_blk - > qno ;
for ( j = 0 ; j < 6 ; j + + ) {
uint16_t dc = ( ( enc_blk - > mb [ 0 ] > > 3 ) - 1024 ) > > 2 ;
put_bits ( & enc_blk - > pb , 9 , dc ) ;
put_bits ( & enc_blk - > pb , 1 , enc_blk - > dct_mode ) ;
put_bits ( & enc_blk - > pb , 2 , enc_blk - > cno ) ;
# ifdef VLC_DEBUG
printf ( " [%d, %d]: " , i , j ) ;
# endif
dv_encode_ac ( enc_blk , & extra_mb ) ;
# ifdef VLC_DEBUG
printf ( " \n " ) ;
# endif
free_mb_bits + = dv_bits_left ( enc_blk ) ;
enc_blk + + ;
}
/* We can't flush extra_mb just yet -- since it'll round up bit number */
extra_bits = get_bit_count ( & extra_mb ) ;
if ( free_mb_bits > extra_bits )
free_vs_bits + = free_mb_bits - extra_bits ;
if ( extra_bits ) { /* FIXME: speed up things when free_mb_bits == 0 */
flush_put_bits ( & extra_mb ) ;
dv_redistr_bits ( enc_blk2 , 6 , extra_mb_data , extra_bits , & extra_vs ) ;
}
}
/* We can't flush extra_mb just yet -- since it'll round up bit number */
extra_bits = get_bit_count ( & extra_vs ) ;
if ( extra_bits > free_vs_bits & & QNO ) { /* FIXME: very crude trial-and-error */
QNO - - ;
goto encode_vs ;
}
if ( extra_bits ) {
flush_put_bits ( & extra_vs ) ;
dv_redistr_bits ( & enc_blks [ 0 ] , 5 * 6 , extra_vs_data , extra_bits , NULL ) ;
}
for ( i = 0 ; i < 6 * 5 ; i + + ) {
flush_put_bits ( & enc_blks [ i ] . pb ) ;
# ifdef VLC_DEBUG
printf ( " [%d:%d] qno=%d cno=%d \n " , i / 6 , i % 6 , enc_blks [ i ] . qno , enc_blks [ i ] . cno ) ;
# endif
}
}
/* NOTE: exactly one frame must be given (120000 bytes for NTSC,
144000 bytes for PAL ) */
static int dvvideo_decode_frame ( AVCodecContext * avctx ,
@ -535,6 +859,9 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
if ( ( vs % 3 ) = = 0 )
buf + = 80 ; /* skip audio block */
# ifdef VLC_DEBUG
printf ( " ********************* %d, %d ********************** \n " , ds , vs ) ;
# endif
dv_decode_video_segment ( s , buf , mb_pos_ptr ) ;
buf + = 5 * 80 ;
mb_pos_ptr + = 5 ;
@ -550,10 +877,45 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
return s - > sys - > frame_size ;
}
static int dvvideo_decode_end ( AVCodecContext * avctx )
static int dvvideo_encode_frame ( AVCodecContext * c , uint8_t * buf , int buf_size ,
void * data )
{
avcodec_default_free_buffers ( avctx ) ;
DVVideoDecodeContext * s = c - > priv_data ;
const uint16_t * mb_pos_ptr ;
int ds , vs ;
s - > sys = dv_codec_profile ( c ) ;
if ( ! s - > sys )
return - 1 ;
c - > pix_fmt = s - > sys - > pix_fmt ;
s - > picture = * ( ( AVFrame * ) data ) ;
/* for each DIF segment */
mb_pos_ptr = s - > sys - > video_place ;
for ( ds = 0 ; ds < s - > sys - > difseg_size ; ds + + ) {
buf + = 6 * 80 ; /* skip DIF segment header */
for ( vs = 0 ; vs < 27 ; vs + + ) {
if ( ( vs % 3 ) = = 0 )
buf + = 80 ; /* skip audio block */
# ifdef VLC_DEBUG
printf ( " ********************* %d, %d ********************** \n " , ds , vs ) ;
# endif
dv_encode_video_segment ( s , buf , mb_pos_ptr ) ;
buf + = 5 * 80 ;
mb_pos_ptr + = 5 ;
}
}
emms_c ( ) ;
return s - > sys - > frame_size ;
}
static int dvvideo_end ( AVCodecContext * avctx )
{
avcodec_default_free_buffers ( avctx ) ;
return 0 ;
}
@ -562,9 +924,9 @@ AVCodec dvvideo_decoder = {
CODEC_TYPE_VIDEO ,
CODEC_ID_DVVIDEO ,
sizeof ( DVVideoDecodeContext ) ,
dvvideo_decode_ init ,
NULL ,
dvvideo_decode_ end ,
dvvideo_init ,
dvvideo_encode_frame ,
dvvideo_end ,
dvvideo_decode_frame ,
CODEC_CAP_DR1 ,
NULL