2008-04-29 03:24:33 +04:00
/*
* cx18 Vertical Blank Interval support functions
*
* Derived from ivtv - vbi . c
*
* Copyright ( C ) 2007 Hans Verkuil < hverkuil @ xs4all . nl >
*
* 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 - 1307 USA
*/
# include "cx18-driver.h"
# include "cx18-vbi.h"
# include "cx18-ioctl.h"
# include "cx18-queue.h"
2009-01-31 06:33:02 +03:00
/*
* Raster Reference / Protection ( RP ) bytes , used in Start / End Active
* Video codes emitted from the digitzer in VIP 1. x mode , that flag the start
* of VBI sample or VBI ancilliary data regions in the digitial ratser line .
*
* Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
*/
static const u8 raw_vbi_sav_rp [ 2 ] = { 0x20 , 0x60 } ; /* __V_, _FV_ */
static const u8 sliced_vbi_eav_rp [ 2 ] = { 0xb0 , 0xf0 } ; /* T_VH, TFVH */
2008-04-29 03:24:33 +04:00
static void copy_vbi_data ( struct cx18 * cx , int lines , u32 pts_stamp )
{
int line = 0 ;
int i ;
u32 linemask [ 2 ] = { 0 , 0 } ;
unsigned short size ;
static const u8 mpeg_hdr_data [ ] = {
2009-01-31 06:33:02 +03:00
/* MPEG-2 Program Pack */
0x00 , 0x00 , 0x01 , 0xba , /* Prog Pack start code */
0x44 , 0x00 , 0x0c , 0x66 , 0x24 , 0x01 , /* SCR, SCR Ext, markers */
0x01 , 0xd1 , 0xd3 , /* Mux Rate, markers */
0xfa , 0xff , 0xff , /* Res, Suff cnt, Stuff */
/* MPEG-2 Private Stream 1 PES Packet */
0x00 , 0x00 , 0x01 , 0xbd , /* Priv Stream 1 start */
0x00 , 0x1a , /* length */
0x84 , 0x80 , 0x07 , /* flags, hdr data len */
0x21 , 0x00 , 0x5d , 0x63 , 0xa7 , /* PTS, markers */
0xff , 0xff /* stuffing */
2008-04-29 03:24:33 +04:00
} ;
const int sd = sizeof ( mpeg_hdr_data ) ; /* start of vbi data */
int idx = cx - > vbi . frame % CX18_VBI_FRAMES ;
u8 * dst = & cx - > vbi . sliced_mpeg_data [ idx ] [ 0 ] ;
for ( i = 0 ; i < lines ; i + + ) {
struct v4l2_sliced_vbi_data * sdata = cx - > vbi . sliced_data + i ;
int f , l ;
if ( sdata - > id = = 0 )
continue ;
l = sdata - > line - 6 ;
f = sdata - > field ;
if ( f )
l + = 18 ;
if ( l < 32 )
linemask [ 0 ] | = ( 1 < < l ) ;
else
linemask [ 1 ] | = ( 1 < < ( l - 32 ) ) ;
2008-04-30 04:38:51 +04:00
dst [ sd + 12 + line * 43 ] = cx18_service2vbi ( sdata - > id ) ;
2008-04-29 03:24:33 +04:00
memcpy ( dst + sd + 12 + line * 43 + 1 , sdata - > data , 42 ) ;
line + + ;
}
memcpy ( dst , mpeg_hdr_data , sizeof ( mpeg_hdr_data ) ) ;
if ( line = = 36 ) {
/* All lines are used, so there is no space for the linemask
( the max size of the VBI data is 36 * 43 + 4 bytes ) .
So in this case we use the magic number ' ITV0 ' . */
memcpy ( dst + sd , " ITV0 " , 4 ) ;
memcpy ( dst + sd + 4 , dst + sd + 12 , line * 43 ) ;
size = 4 + ( ( 43 * line + 3 ) & ~ 3 ) ;
} else {
2009-01-31 06:33:02 +03:00
memcpy ( dst + sd , " itv0 " , 4 ) ;
2009-03-15 02:03:26 +03:00
cpu_to_le32s ( & linemask [ 0 ] ) ;
cpu_to_le32s ( & linemask [ 1 ] ) ;
2008-04-29 03:24:33 +04:00
memcpy ( dst + sd + 4 , & linemask [ 0 ] , 8 ) ;
size = 12 + ( ( 43 * line + 3 ) & ~ 3 ) ;
}
dst [ 4 + 16 ] = ( size + 10 ) > > 8 ;
dst [ 5 + 16 ] = ( size + 10 ) & 0xff ;
dst [ 9 + 16 ] = 0x21 | ( ( pts_stamp > > 29 ) & 0x6 ) ;
dst [ 10 + 16 ] = ( pts_stamp > > 22 ) & 0xff ;
dst [ 11 + 16 ] = 1 | ( ( pts_stamp > > 14 ) & 0xff ) ;
dst [ 12 + 16 ] = ( pts_stamp > > 7 ) & 0xff ;
dst [ 13 + 16 ] = 1 | ( ( pts_stamp & 0x7f ) < < 1 ) ;
cx - > vbi . sliced_mpeg_size [ idx ] = sd + size ;
}
/* Compress raw VBI format, removes leading SAV codes and surplus space
2009-02-07 21:47:28 +03:00
after the frame . Returns new compressed size . */
2009-03-15 05:20:49 +03:00
static u32 compress_raw_buf ( struct cx18 * cx , u8 * buf , u32 size , u32 hdr_size )
2008-04-29 03:24:33 +04:00
{
2009-01-31 06:33:02 +03:00
u32 line_size = vbi_active_samples ;
2009-02-07 21:47:28 +03:00
u32 lines = cx - > vbi . count * 2 ;
2008-04-29 03:24:33 +04:00
u8 * q = buf ;
u8 * p ;
int i ;
2009-03-15 05:20:49 +03:00
/* Skip the header */
buf + = hdr_size ;
2008-04-29 03:24:33 +04:00
for ( i = 0 ; i < lines ; i + + ) {
p = buf + i * line_size ;
/* Look for SAV code */
if ( p [ 0 ] ! = 0xff | | p [ 1 ] | | p [ 2 ] | |
2009-03-15 05:20:49 +03:00
( p [ 3 ] ! = raw_vbi_sav_rp [ 0 ] & &
p [ 3 ] ! = raw_vbi_sav_rp [ 1 ] ) )
2008-04-29 03:24:33 +04:00
break ;
2009-03-15 05:20:49 +03:00
if ( i = = lines - 1 ) {
/* last line is hdr_size bytes short - extrapolate it */
memcpy ( q , p + 4 , line_size - 4 - hdr_size ) ;
q + = line_size - 4 - hdr_size ;
p + = line_size - hdr_size - 1 ;
memset ( q , ( int ) * p , hdr_size ) ;
} else {
memcpy ( q , p + 4 , line_size - 4 ) ;
q + = line_size - 4 ;
}
2008-04-29 03:24:33 +04:00
}
return lines * ( line_size - 4 ) ;
}
2009-03-15 05:20:49 +03:00
static u32 compress_sliced_buf ( struct cx18 * cx , u8 * buf , u32 size ,
const u32 hdr_size )
2008-04-29 03:24:33 +04:00
{
struct v4l2_decode_vbi_line vbi ;
int i ;
2009-03-15 05:20:49 +03:00
u32 line = 0 ;
2009-01-31 06:33:02 +03:00
u32 line_size = cx - > is_60hz ? vbi_hblank_samples_60Hz
: vbi_hblank_samples_50Hz ;
2008-04-29 03:24:33 +04:00
/* find the first valid line */
2009-03-15 05:20:49 +03:00
for ( i = hdr_size , buf + = hdr_size ; i < size ; i + + , buf + + ) {
if ( buf [ 0 ] = = 0xff & & ! buf [ 1 ] & & ! buf [ 2 ] & &
( buf [ 3 ] = = sliced_vbi_eav_rp [ 0 ] | |
buf [ 3 ] = = sliced_vbi_eav_rp [ 1 ] ) )
2008-04-29 03:24:33 +04:00
break ;
}
2009-03-15 05:20:49 +03:00
/*
* The last line is short by hdr_size bytes , but for the remaining
* checks against size , we pretend that it is not , by counting the
* header bytes we knowingly skipped
*/
size - = ( i - hdr_size ) ;
2008-04-29 03:24:33 +04:00
if ( size < line_size )
return line ;
2009-03-15 05:20:49 +03:00
2008-04-29 03:24:33 +04:00
for ( i = 0 ; i < size / line_size ; i + + ) {
u8 * p = buf + i * line_size ;
2009-01-31 06:33:02 +03:00
/* Look for EAV code */
2009-03-15 05:20:49 +03:00
if ( p [ 0 ] ! = 0xff | | p [ 1 ] | | p [ 2 ] | |
( p [ 3 ] ! = sliced_vbi_eav_rp [ 0 ] & &
p [ 3 ] ! = sliced_vbi_eav_rp [ 1 ] ) )
2008-04-29 03:24:33 +04:00
continue ;
vbi . p = p + 4 ;
2009-02-16 08:23:25 +03:00
v4l2_subdev_call ( cx - > sd_av , video , decode_vbi_line , & vbi ) ;
2008-04-29 03:24:33 +04:00
if ( vbi . type ) {
cx - > vbi . sliced_data [ line ] . id = vbi . type ;
cx - > vbi . sliced_data [ line ] . field = vbi . is_second_field ;
cx - > vbi . sliced_data [ line ] . line = vbi . line ;
memcpy ( cx - > vbi . sliced_data [ line ] . data , vbi . p , 42 ) ;
line + + ;
}
}
return line ;
}
void cx18_process_vbi_data ( struct cx18 * cx , struct cx18_buffer * buf ,
2009-02-02 03:42:12 +03:00
int streamtype )
2008-04-29 03:24:33 +04:00
{
2009-03-15 05:20:49 +03:00
/*
* The CX23418 provides a 12 byte header in its raw VBI buffers to us :
* 0x3fffffff [ 4 bytes of something ] [ 4 byte presentation time stamp ]
*/
struct vbi_data_hdr {
__be32 magic ;
__be32 unknown ;
__be32 pts ;
} * hdr = ( struct vbi_data_hdr * ) buf - > buf ;
2008-04-29 03:24:33 +04:00
u8 * p = ( u8 * ) buf - > buf ;
u32 size = buf - > bytesused ;
2009-02-02 03:42:12 +03:00
u32 pts ;
2008-04-29 03:24:33 +04:00
int lines ;
if ( streamtype ! = CX18_ENC_STREAM_TYPE_VBI )
return ;
2009-02-07 07:31:22 +03:00
/*
2009-03-01 00:48:27 +03:00
* The CX23418 sends us data that is 32 bit little - endian swapped ,
* but we want the raw VBI bytes in the order they were in the raster
2009-03-15 05:20:49 +03:00
* line . This has a side effect of making the header big endian
2009-02-07 07:31:22 +03:00
*/
2009-02-02 03:42:12 +03:00
cx18_buf_swap ( buf ) ;
2008-04-29 03:24:33 +04:00
/* Raw VBI data */
2008-12-12 22:24:04 +03:00
if ( cx18_raw_vbi ( cx ) ) {
2008-04-29 03:24:33 +04:00
2009-03-15 05:20:49 +03:00
size = buf - > bytesused =
compress_raw_buf ( cx , p , size , sizeof ( struct vbi_data_hdr ) ) ;
2008-04-29 03:24:33 +04:00
2009-02-07 21:47:28 +03:00
/*
* Hack needed for compatibility with old VBI software .
* Write the frame # at the last 4 bytes of the frame
*/
p + = size - 4 ;
memcpy ( p , & cx - > vbi . frame , 4 ) ;
cx - > vbi . frame + + ;
2008-04-29 03:24:33 +04:00
return ;
}
/* Sliced VBI data with data insertion */
2009-02-02 03:42:12 +03:00
2009-03-15 05:20:49 +03:00
pts = ( be32_to_cpu ( hdr - > magic ) = = 0x3fffffff ) ? be32_to_cpu ( hdr - > pts )
: 0 ;
2008-04-29 03:24:33 +04:00
2009-03-15 05:20:49 +03:00
lines = compress_sliced_buf ( cx , p , size , sizeof ( struct vbi_data_hdr ) ) ;
2009-02-09 04:40:04 +03:00
2008-04-29 03:24:33 +04:00
/* always return at least one empty line */
if ( lines = = 0 ) {
cx - > vbi . sliced_data [ 0 ] . id = 0 ;
cx - > vbi . sliced_data [ 0 ] . line = 0 ;
cx - > vbi . sliced_data [ 0 ] . field = 0 ;
lines = 1 ;
}
buf - > bytesused = size = lines * sizeof ( cx - > vbi . sliced_data [ 0 ] ) ;
memcpy ( p , & cx - > vbi . sliced_data [ 0 ] , size ) ;
if ( cx - > vbi . insert_mpeg )
2009-02-02 03:42:12 +03:00
copy_vbi_data ( cx , lines , pts ) ;
2008-04-29 03:24:33 +04:00
cx - > vbi . frame + + ;
}