29 changed files with 4383 additions and 14 deletions
@ -0,0 +1,2 @@ |
|||
.deps |
|||
.dirstamp |
|||
@ -0,0 +1,3 @@ |
|||
SOURCES_access_output_dummy = modules/access_output/dummy.c |
|||
SOURCES_access_output_file = modules/access_output/file.c |
|||
SOURCES_access_output_udp = modules/access_output/udp.c |
|||
@ -0,0 +1,121 @@ |
|||
/*****************************************************************************
|
|||
* dummy.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: dummy.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static int Open ( vlc_object_t * ); |
|||
static void Close ( vlc_object_t * ); |
|||
|
|||
static int Write( sout_instance_t *, sout_buffer_t * ); |
|||
static int Seek( sout_instance_t *, off_t ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
vlc_module_begin(); |
|||
set_description( _("Dummy stream ouput") ); |
|||
set_capability( "sout access", 0 ); |
|||
add_shortcut( "dummy" ); |
|||
set_callbacks( Open, Close ); |
|||
vlc_module_end(); |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* Open: open the file |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
|
|||
p_sout->i_method = SOUT_METHOD_NONE; |
|||
p_sout->p_access_data = NULL; |
|||
p_sout->pf_write = Write; |
|||
p_sout->pf_seek = Seek; |
|||
|
|||
msg_Info( p_sout, "dummy stream output access launched" ); |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Close: close the target |
|||
*****************************************************************************/ |
|||
static void Close( vlc_object_t * p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
msg_Info( p_sout, "Close" ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Read: standard read on a file descriptor. |
|||
*****************************************************************************/ |
|||
static int Write( sout_instance_t *p_sout, sout_buffer_t *p_buffer ) |
|||
{ |
|||
size_t i_write = 0; |
|||
|
|||
do |
|||
{ |
|||
sout_buffer_t *p_next; |
|||
i_write += p_buffer->i_size; |
|||
p_next = p_buffer->p_next; |
|||
sout_BufferDelete( p_sout, p_buffer ); |
|||
p_buffer = p_next; |
|||
} while( p_buffer ); |
|||
|
|||
msg_Dbg( p_sout, "Dummy Skipped: len:%d", (uint32_t)i_write ); |
|||
|
|||
return( i_write ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Seek: seek to a specific location in a file |
|||
*****************************************************************************/ |
|||
static int Seek( sout_instance_t *p_sout, off_t i_pos ) |
|||
{ |
|||
msg_Dbg( p_sout, "Seek: pos:%lld", (int64_t)i_pos ); |
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,151 @@ |
|||
/*****************************************************************************
|
|||
* file.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: file.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static int Open ( vlc_object_t * ); |
|||
static void Close ( vlc_object_t * ); |
|||
|
|||
static int Write( sout_instance_t *, sout_buffer_t * ); |
|||
static int Seek( sout_instance_t *, off_t ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
vlc_module_begin(); |
|||
set_description( _("File stream ouput") ); |
|||
set_capability( "sout access", 50 ); |
|||
add_shortcut( "file" ); |
|||
set_callbacks( Open, Close ); |
|||
vlc_module_end(); |
|||
|
|||
typedef struct sout_access_data_s |
|||
{ |
|||
FILE *p_file; |
|||
|
|||
} sout_access_data_t; |
|||
|
|||
/*****************************************************************************
|
|||
* Open: open the file |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_access_data_t *p_access; |
|||
char * psz_name = p_sout->psz_name; |
|||
|
|||
p_access = malloc( sizeof( sout_access_data_t ) ); |
|||
|
|||
if( !( p_access->p_file = fopen( psz_name, "wb" ) ) ) |
|||
{ |
|||
msg_Err( p_sout, "cannot open `%s'", psz_name ); |
|||
free( p_access ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
p_sout->i_method = SOUT_METHOD_FILE; |
|||
p_sout->p_access_data = p_access; |
|||
p_sout->pf_write = Write; |
|||
p_sout->pf_seek = Seek; |
|||
|
|||
msg_Info( p_sout, "Open: name:`%s'", psz_name ); |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Close: close the target |
|||
*****************************************************************************/ |
|||
static void Close( vlc_object_t * p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_access_data_t *p_access = (sout_access_data_t*)p_sout->p_access_data; |
|||
|
|||
if( p_access->p_file ) |
|||
{ |
|||
fclose( p_access->p_file ); |
|||
} |
|||
|
|||
msg_Info( p_sout, "Close" ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Read: standard read on a file descriptor. |
|||
*****************************************************************************/ |
|||
static int Write( sout_instance_t *p_sout, sout_buffer_t *p_buffer ) |
|||
{ |
|||
sout_access_data_t *p_access = (sout_access_data_t*)p_sout->p_access_data; |
|||
size_t i_write = 0; |
|||
|
|||
do |
|||
{ |
|||
sout_buffer_t *p_next; |
|||
|
|||
i_write += fwrite( p_buffer->p_buffer, 1, p_buffer->i_size, |
|||
p_access->p_file ); |
|||
p_next = p_buffer->p_next; |
|||
sout_BufferDelete( p_sout, p_buffer ); |
|||
p_buffer = p_next; |
|||
|
|||
} while( p_buffer ); |
|||
|
|||
msg_Dbg( p_sout, "Write: len:%d", (uint32_t)i_write ); |
|||
|
|||
return( i_write ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Seek: seek to a specific location in a file |
|||
*****************************************************************************/ |
|||
static int Seek( sout_instance_t *p_sout, off_t i_pos ) |
|||
{ |
|||
|
|||
sout_access_data_t *p_access = (sout_access_data_t*)p_sout->p_access_data; |
|||
|
|||
msg_Dbg( p_sout, "Seek: pos:%lld", (int64_t)i_pos ); |
|||
return( fseek( p_access->p_file, i_pos, SEEK_SET ) ); |
|||
} |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,398 @@ |
|||
/*****************************************************************************
|
|||
* udp.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: udp.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#ifdef WIN32 |
|||
# include <winsock2.h> |
|||
# include <ws2tcpip.h> |
|||
# ifndef IN_MULTICAST |
|||
# define IN_MULTICAST(a) IN_CLASSD(a) |
|||
# endif |
|||
#else |
|||
# include <sys/socket.h> |
|||
#endif |
|||
|
|||
#include "network.h" |
|||
|
|||
#define DEFAULT_PORT 1234 |
|||
#define LATENCY 100000 |
|||
#define MAX_ERROR 500000 |
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static int Open ( vlc_object_t * ); |
|||
static void Close ( vlc_object_t * ); |
|||
|
|||
static int Write( sout_instance_t *, sout_buffer_t * ); |
|||
static int Seek( sout_instance_t *, off_t ); |
|||
|
|||
static void ThreadWrite( vlc_object_t *p_this ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
vlc_module_begin(); |
|||
set_description( _("UDP stream ouput") ); |
|||
set_capability( "sout access", 100 ); |
|||
add_shortcut( "udp" ); |
|||
add_shortcut( "rtp" ); // Will work only with ts muxer
|
|||
set_callbacks( Open, Close ); |
|||
vlc_module_end(); |
|||
|
|||
typedef struct sout_access_thread_s |
|||
{ |
|||
VLC_COMMON_MEMBERS |
|||
|
|||
sout_instance_t *p_sout; |
|||
|
|||
sout_fifo_t *p_fifo; |
|||
|
|||
int i_handle; |
|||
|
|||
} sout_access_thread_t; |
|||
|
|||
typedef struct sout_access_data_s |
|||
{ |
|||
int b_rtpts; // 1 if add rtp/ts header
|
|||
uint16_t i_sequence_number; |
|||
uint32_t i_ssrc; |
|||
|
|||
int i_mtu; |
|||
|
|||
sout_buffer_t *p_buffer; |
|||
|
|||
sout_access_thread_t *p_thread; |
|||
|
|||
} sout_access_data_t; |
|||
|
|||
/*****************************************************************************
|
|||
* Open: open the file |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_access_data_t *p_access; |
|||
|
|||
char *psz_parser; |
|||
char *psz_dst_addr; |
|||
int i_dst_port; |
|||
|
|||
module_t *p_network; |
|||
network_socket_t socket_desc; |
|||
|
|||
if( !( p_access = malloc( sizeof( sout_access_data_t ) ) ) ) |
|||
{ |
|||
msg_Err( p_sout, "Not enough memory" ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
if( p_sout->psz_access != NULL && |
|||
!strcmp( p_sout->psz_access, "rtp" ) ) |
|||
{ |
|||
if( p_sout->psz_mux != NULL && |
|||
strcmp( p_sout->psz_mux, "ts" ) ) |
|||
{ |
|||
msg_Err( p_sout, "rtp ouput work only with ts payload" ); |
|||
free( p_access ); |
|||
return( -1 ); |
|||
} |
|||
p_access->b_rtpts = 1; |
|||
} |
|||
else |
|||
{ |
|||
p_access->b_rtpts = 0; |
|||
} |
|||
|
|||
psz_parser = strdup( p_sout->psz_name ); |
|||
|
|||
psz_dst_addr = psz_parser; |
|||
i_dst_port = 0; |
|||
|
|||
while( *psz_parser && *psz_parser != ':' ) |
|||
{ |
|||
psz_parser++; |
|||
} |
|||
if( *psz_parser == ':' ) |
|||
{ |
|||
*psz_parser = '\0'; |
|||
psz_parser++; |
|||
i_dst_port = atoi( psz_parser ); |
|||
} |
|||
if( i_dst_port <= 0 ) |
|||
{ |
|||
i_dst_port = DEFAULT_PORT; |
|||
} |
|||
|
|||
p_access->p_thread = vlc_object_create( p_sout, |
|||
sizeof( sout_access_thread_t ) ); |
|||
if( !p_access->p_thread ) |
|||
{ |
|||
msg_Err( p_sout, "out of memory" ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
p_access->p_thread->p_sout = p_sout; |
|||
p_access->p_thread->b_die = 0; |
|||
p_access->p_thread->b_error= 0; |
|||
p_access->p_thread->p_fifo = sout_FifoCreate( p_sout ); |
|||
|
|||
socket_desc.i_type = NETWORK_UDP; |
|||
socket_desc.psz_server_addr = psz_dst_addr; |
|||
socket_desc.i_server_port = i_dst_port; |
|||
socket_desc.psz_bind_addr = ""; |
|||
socket_desc.i_bind_port = 0; |
|||
p_access->p_thread->p_private = (void*)&socket_desc; |
|||
if( !( p_network = module_Need( p_access->p_thread, |
|||
"network", "" ) ) ) |
|||
{ |
|||
msg_Err( p_sout, "failed to open a connection (udp)" ); |
|||
return( -1 ); |
|||
} |
|||
module_Unneed( p_access->p_thread, p_network ); |
|||
|
|||
p_access->p_thread->i_handle = socket_desc.i_handle; |
|||
p_access->i_mtu = socket_desc.i_mtu; |
|||
|
|||
if( vlc_thread_create( p_access->p_thread, "sout write thread", |
|||
ThreadWrite, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) ) |
|||
{ |
|||
msg_Err( p_sout, "cannot spawn sout access thread" ); |
|||
vlc_object_destroy( p_access->p_thread ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
p_access->p_buffer = NULL; |
|||
p_access->i_sequence_number = 12; // FIXME should be random, used by rtp
|
|||
p_access->i_ssrc = 4212; // FIXME " " " " " "
|
|||
|
|||
p_sout->i_method = SOUT_METHOD_NETWORK; |
|||
p_sout->p_access_data = (void*)p_access; |
|||
p_sout->pf_write = Write; |
|||
p_sout->pf_seek = Seek; |
|||
|
|||
msg_Info( p_sout, |
|||
"Open: addr:`%s' port:`%d'", |
|||
psz_dst_addr, i_dst_port ); |
|||
|
|||
free( psz_dst_addr ); |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Close: close the target |
|||
*****************************************************************************/ |
|||
static void Close( vlc_object_t * p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_access_data_t *p_access = (sout_access_data_t*)p_sout->p_access_data; |
|||
int i; |
|||
|
|||
p_access->p_thread->b_die = 1; |
|||
for( i = 0; i < 10; i++ ) |
|||
{ |
|||
sout_buffer_t *p_dummy; |
|||
|
|||
p_dummy = sout_BufferNew( p_sout, p_access->i_mtu ); |
|||
p_dummy->i_dts = 0; |
|||
p_dummy->i_pts = 0; |
|||
p_dummy->i_length = 0; |
|||
sout_FifoPut( p_access->p_thread->p_fifo, p_dummy ); |
|||
} |
|||
vlc_thread_join( p_access->p_thread ); |
|||
|
|||
sout_FifoDestroy( p_sout, p_access->p_thread->p_fifo ); |
|||
|
|||
if( p_access->p_buffer ) |
|||
{ |
|||
sout_BufferDelete( p_sout, p_access->p_buffer ); |
|||
} |
|||
|
|||
#if defined( UNDER_CE ) |
|||
CloseHandle( (HANDLE)p_access->p_thread->i_handle ); |
|||
#elif defined( WIN32 ) |
|||
closesocket( p_access->p_thread->i_handle ); |
|||
#else |
|||
close( p_access->p_thread->i_handle ); |
|||
#endif |
|||
msg_Info( p_sout, "Close" ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Read: standard read on a file descriptor. |
|||
*****************************************************************************/ |
|||
static int Write( sout_instance_t *p_sout, sout_buffer_t *p_buffer ) |
|||
{ |
|||
sout_access_data_t *p_access = (sout_access_data_t*)p_sout->p_access_data; |
|||
int i_write; |
|||
|
|||
while( p_buffer ) |
|||
{ |
|||
sout_buffer_t *p_next; |
|||
if( p_buffer->i_size > p_access->i_mtu ) |
|||
{ |
|||
msg_Warn( p_sout, "arggggggggggggg packet size > mtu" ); |
|||
i_write = p_access->i_mtu; |
|||
} |
|||
else |
|||
{ |
|||
i_write = p_buffer->i_size; |
|||
} |
|||
|
|||
/* if we have enough data, enque the buffer */ |
|||
if( p_access->p_buffer && |
|||
p_access->p_buffer->i_size + i_write > p_access->i_mtu ) |
|||
{ |
|||
sout_FifoPut( p_access->p_thread->p_fifo, p_access->p_buffer ); |
|||
p_access->p_buffer = NULL; |
|||
} |
|||
|
|||
if( !p_access->p_buffer ) |
|||
{ |
|||
p_access->p_buffer = sout_BufferNew( p_sout, p_access->i_mtu ); |
|||
p_access->p_buffer->i_dts = p_buffer->i_dts; |
|||
p_access->p_buffer->i_size = 0; |
|||
if( p_access->b_rtpts ) |
|||
{ |
|||
mtime_t i_timestamp = p_access->p_buffer->i_dts * 9 / 100; |
|||
|
|||
/* add rtp/ts header */ |
|||
p_access->p_buffer->p_buffer[0] = 0x80; |
|||
p_access->p_buffer->p_buffer[1] = 0x21; // mpeg2-ts
|
|||
p_access->p_buffer->p_buffer[2] = |
|||
( p_access->i_sequence_number >> 8 )&0xff; |
|||
p_access->p_buffer->p_buffer[3] = |
|||
p_access->i_sequence_number&0xff; |
|||
|
|||
p_access->p_buffer->p_buffer[4] = ( i_timestamp >> 24 )&0xff; |
|||
p_access->p_buffer->p_buffer[5] = ( i_timestamp >> 16 )&0xff; |
|||
p_access->p_buffer->p_buffer[6] = ( i_timestamp >> 8 )&0xff; |
|||
p_access->p_buffer->p_buffer[7] = i_timestamp&0xff; |
|||
|
|||
p_access->p_buffer->p_buffer[ 8] = |
|||
( p_access->i_ssrc >> 24 )&0xff; |
|||
p_access->p_buffer->p_buffer[ 9] = |
|||
( p_access->i_ssrc >> 16 )&0xff; |
|||
p_access->p_buffer->p_buffer[10] = |
|||
( p_access->i_ssrc >> 8 )&0xff; |
|||
p_access->p_buffer->p_buffer[11] = p_access->i_ssrc&0xff; |
|||
|
|||
p_access->p_buffer->i_size = 12; |
|||
} |
|||
} |
|||
|
|||
|
|||
if( p_buffer->i_size > 0 ) |
|||
{ |
|||
memcpy( p_access->p_buffer->p_buffer + p_access->p_buffer->i_size, |
|||
p_buffer->p_buffer, |
|||
i_write ); |
|||
p_access->p_buffer->i_size += i_write; |
|||
} |
|||
p_next = p_buffer->p_next; |
|||
sout_BufferDelete( p_sout, p_buffer ); |
|||
p_buffer = p_next; |
|||
} |
|||
|
|||
return( p_access->p_thread->b_error ? -1 : 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Seek: seek to a specific location in a file |
|||
*****************************************************************************/ |
|||
static int Seek( sout_instance_t *p_sout, off_t i_pos ) |
|||
{ |
|||
|
|||
msg_Err( p_sout, "udp sout access cannot seek" ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* ThreadWrite: Write a packet on the network at the good time. |
|||
*****************************************************************************/ |
|||
static void ThreadWrite( vlc_object_t *p_this ) |
|||
{ |
|||
sout_access_thread_t *p_thread = (sout_access_thread_t*)p_this; |
|||
sout_instance_t *p_sout = p_thread->p_sout; |
|||
sout_buffer_t *p_buffer; |
|||
mtime_t i_date; |
|||
|
|||
while( !p_thread->b_die && p_thread->p_fifo->i_depth < 5 ) |
|||
{ |
|||
msleep( 10000 ); |
|||
} |
|||
if( p_thread->b_die ) |
|||
{ |
|||
return; |
|||
} |
|||
p_buffer = sout_FifoShow( p_thread->p_fifo ); |
|||
i_date = mdate() - p_buffer->i_dts; |
|||
|
|||
for( ;; ) |
|||
{ |
|||
mtime_t i_wait; |
|||
|
|||
p_buffer = sout_FifoGet( p_thread->p_fifo ); |
|||
|
|||
if( p_thread->b_die ) |
|||
{ |
|||
return; |
|||
} |
|||
i_wait = i_date + p_buffer->i_dts; |
|||
mwait( i_wait ); |
|||
|
|||
if( i_wait - mdate() > MAX_ERROR || |
|||
i_wait - mdate() < -MAX_ERROR ) |
|||
{ |
|||
msg_Warn( p_sout, "resetting clock" ); |
|||
i_date = mdate() - p_buffer->i_dts; |
|||
} |
|||
send( p_thread->i_handle, |
|||
p_buffer->p_buffer, |
|||
p_buffer->i_size, |
|||
0 ); |
|||
|
|||
sout_BufferDelete( p_sout, p_buffer ); |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,2 @@ |
|||
.deps |
|||
.dirstamp |
|||
@ -0,0 +1 @@ |
|||
SOURCES_mux_dummy = modules/mux/dummy.c |
|||
@ -0,0 +1,131 @@ |
|||
/*****************************************************************************
|
|||
* dummy.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: dummy.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#include "codecs.h" |
|||
|
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static int Open ( vlc_object_t * ); |
|||
static void Close ( vlc_object_t * ); |
|||
|
|||
static int AddStream( sout_instance_t *, sout_input_t * ); |
|||
static int DelStream( sout_instance_t *, sout_input_t * ); |
|||
static int Mux ( sout_instance_t * ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
vlc_module_begin(); |
|||
set_description( _("Dummy muxer") ); |
|||
set_capability( "sout mux", 5 ); |
|||
add_shortcut( "dummy" ); |
|||
set_callbacks( Open, Close ); |
|||
vlc_module_end(); |
|||
|
|||
/*****************************************************************************
|
|||
* Open: |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
|
|||
msg_Info( p_sout, "Open" ); |
|||
|
|||
p_sout->pf_mux_addstream = AddStream; |
|||
p_sout->pf_mux_delstream = DelStream; |
|||
p_sout->pf_mux = Mux; |
|||
|
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Close: |
|||
*****************************************************************************/ |
|||
|
|||
static void Close( vlc_object_t * p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
msg_Info( p_sout, "Close" ); |
|||
} |
|||
|
|||
|
|||
static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input ) |
|||
{ |
|||
msg_Dbg( p_sout, "adding input" ); |
|||
return( 0 ); |
|||
} |
|||
|
|||
static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input ) |
|||
{ |
|||
|
|||
msg_Dbg( p_sout, "removing input" ); |
|||
return( 0 ); |
|||
} |
|||
|
|||
static int Mux ( sout_instance_t *p_sout ) |
|||
{ |
|||
int i; |
|||
for( i = 0; i < p_sout->i_nb_inputs; i++ ) |
|||
{ |
|||
int i_count; |
|||
sout_fifo_t *p_fifo; |
|||
|
|||
p_fifo = p_sout->pp_inputs[i]->p_fifo; |
|||
i_count = p_fifo->i_depth; |
|||
while( i_count > 0 ) |
|||
{ |
|||
sout_buffer_t *p_data; |
|||
|
|||
p_data = sout_FifoGet( p_fifo ); |
|||
|
|||
p_sout->pf_write( p_sout, p_data ); |
|||
|
|||
i_count--; |
|||
} |
|||
|
|||
} |
|||
return( 0 ); |
|||
} |
|||
|
|||
@ -0,0 +1,2 @@ |
|||
.deps |
|||
.dirstamp |
|||
@ -0,0 +1,12 @@ |
|||
SOURCES_mux_ps = modules/mux/mpeg/ps.c \ |
|||
modules/mux/mpeg/pes.c \ |
|||
modules/mux/mpeg/pes.h \ |
|||
modules/mux/mpeg/bits.h \ |
|||
$(NULL) |
|||
SOURCES_mux_ts = modules/mux/mpeg/ts.c \ |
|||
modules/mux/mpeg/pes.c \ |
|||
modules/mux/mpeg/pes.h \ |
|||
modules/mux/mpeg/bits.h \ |
|||
$(NULL) |
|||
|
|||
|
|||
@ -0,0 +1,93 @@ |
|||
/*****************************************************************************
|
|||
* bits.h |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: bits.h,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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. |
|||
*****************************************************************************/ |
|||
|
|||
typedef struct bits_buffer_s |
|||
{ |
|||
int i_size; |
|||
|
|||
int i_data; |
|||
uint8_t i_mask; |
|||
uint8_t *p_data; |
|||
|
|||
} bits_buffer_t; |
|||
|
|||
static inline int bits_initwrite( bits_buffer_t *p_buffer, |
|||
int i_size, void *p_data ) |
|||
{ |
|||
p_buffer->i_size = i_size; |
|||
p_buffer->i_data = 0; |
|||
p_buffer->i_mask = 0x80; |
|||
p_buffer->p_data = p_data; |
|||
p_buffer->p_data[0] = 0; |
|||
if( !p_buffer->p_data ) |
|||
{ |
|||
if( !( p_buffer->p_data = malloc( i_size ) ) ) |
|||
{ |
|||
return( -1 ); |
|||
} |
|||
else |
|||
{ |
|||
return( 0 ); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
return( 0 ); |
|||
} |
|||
} |
|||
|
|||
static inline void bits_align( bits_buffer_t *p_buffer ) |
|||
{ |
|||
if( p_buffer->i_mask != 0x80 && p_buffer->i_data < p_buffer->i_size ) |
|||
{ |
|||
p_buffer->i_mask = 0x80; |
|||
p_buffer->i_data++; |
|||
p_buffer->p_data[p_buffer->i_data] = 0x00; |
|||
} |
|||
} |
|||
|
|||
static inline void bits_write( bits_buffer_t *p_buffer, |
|||
int i_count, uint64_t i_bits ) |
|||
{ |
|||
while( i_count > 0 ) |
|||
{ |
|||
if( i_bits & ( 1 << ( i_count - 1 ) ) ) |
|||
{ |
|||
p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask; |
|||
} |
|||
p_buffer->i_mask >>= 1; |
|||
if( p_buffer->i_mask == 0 ) |
|||
{ |
|||
p_buffer->i_data++; |
|||
if( p_buffer->i_data < p_buffer->i_size ) |
|||
{ |
|||
p_buffer->p_data[p_buffer->i_data] = 0; |
|||
p_buffer->i_mask = 0x80; |
|||
} |
|||
} |
|||
i_count--; |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,208 @@ |
|||
/*****************************************************************************
|
|||
* pes.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: pes.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#include "codecs.h" |
|||
#include "pes.h" |
|||
#include "bits.h" |
|||
|
|||
int EStoPES( sout_instance_t *p_sout, |
|||
sout_buffer_t **pp_pes, |
|||
sout_buffer_t *p_es, |
|||
int i_stream_id, |
|||
int b_mpeg2 ) |
|||
{ |
|||
sout_buffer_t *p_pes; |
|||
bits_buffer_t bits; |
|||
mtime_t i_pts, i_dts; |
|||
uint8_t *p_data; |
|||
int i_size; |
|||
|
|||
i_pts = p_es->i_pts * 9 / 100; // 90000 units clock
|
|||
i_dts = p_es->i_dts * 9 / 100; // 90000 units clock
|
|||
|
|||
i_size = p_es->i_size; |
|||
p_data = p_es->p_buffer; |
|||
|
|||
*pp_pes = p_pes = NULL; |
|||
|
|||
do |
|||
{ |
|||
int i_copy; |
|||
|
|||
i_copy = __MIN( i_size, 65500 ); |
|||
|
|||
if( *pp_pes == NULL ) |
|||
{ |
|||
*pp_pes = p_pes = sout_BufferNew( p_sout, 100 + i_copy); |
|||
p_pes->i_dts = p_es->i_dts; |
|||
p_pes->i_pts = p_es->i_pts; |
|||
p_pes->i_length = p_es->i_length; |
|||
} |
|||
else |
|||
{ |
|||
p_pes->p_next = sout_BufferNew( p_sout, 100 + i_copy ); |
|||
p_pes = p_pes->p_next; |
|||
|
|||
p_pes->i_dts = 0; |
|||
p_pes->i_pts = 0; |
|||
p_pes->i_length = 0; |
|||
} |
|||
|
|||
p_pes->i_size = 0; |
|||
|
|||
|
|||
bits_initwrite( &bits, 100, p_pes->p_buffer ); |
|||
|
|||
/* first 4 bytes common pes header */ |
|||
/* add start code for pes 0x000001 */ |
|||
bits_write( &bits, 24, 0x01 ); |
|||
/* add stream id */ |
|||
bits_write( &bits, 8, i_stream_id ); |
|||
|
|||
switch( i_stream_id ) |
|||
{ |
|||
case PES_PROGRAM_STREAM_MAP: |
|||
case PES_PADDING: |
|||
case PES_PRIVATE_STREAM_2: |
|||
case PES_ECM: |
|||
case PES_EMM: |
|||
case PES_PROGRAM_STREAM_DIRECTORY: |
|||
case PES_DSMCC_STREAM: |
|||
case PES_ITU_T_H222_1_TYPE_E_STREAM: |
|||
/* add pes data size */ |
|||
bits_write( &bits, 16, i_copy ); |
|||
bits_align( &bits ); |
|||
break; |
|||
|
|||
default: |
|||
/* arg, a little more difficult */ |
|||
if( b_mpeg2 ) |
|||
{ |
|||
int i_pts_dts; |
|||
|
|||
if( i_dts > 0 ) |
|||
{ |
|||
bits_write( &bits, 16, i_copy + 13 ); |
|||
i_pts_dts = 0x03; |
|||
} |
|||
else |
|||
{ |
|||
bits_write( &bits, 16, i_copy + 8 ); |
|||
i_pts_dts = 0x02; |
|||
} |
|||
|
|||
bits_write( &bits, 2, 0x02 ); // mpeg2 id
|
|||
bits_write( &bits, 2, 0x00 ); // pes scrambling control
|
|||
bits_write( &bits, 1, 0x00 ); // pes priority
|
|||
bits_write( &bits, 1, 0x00 ); // data alignement indicator
|
|||
bits_write( &bits, 1, 0x00 ); // copyright
|
|||
bits_write( &bits, 1, 0x00 ); // original or copy
|
|||
|
|||
bits_write( &bits, 2, i_pts_dts ); // pts_dts flags
|
|||
bits_write( &bits, 1, 0x00 ); // escr flags
|
|||
bits_write( &bits, 1, 0x00 ); // es rate flag
|
|||
bits_write( &bits, 1, 0x00 ); // dsm trick mode flag
|
|||
bits_write( &bits, 1, 0x00 ); // additional copy info flag
|
|||
bits_write( &bits, 1, 0x00 ); // pes crc flag
|
|||
bits_write( &bits, 1, 0x00 ); // pes extention flags
|
|||
if( i_pts_dts & 0x01 ) |
|||
{ |
|||
bits_write( &bits, 8, 0x0a ); // header size -> pts and dts
|
|||
} |
|||
else |
|||
{ |
|||
bits_write( &bits, 8, 0x05 ); // header size -> pts
|
|||
} |
|||
|
|||
/* write pts */ |
|||
bits_write( &bits, 4, i_pts_dts ); // '0010' or '0011'
|
|||
bits_write( &bits, 3, i_pts >> 30 ); |
|||
bits_write( &bits, 1, 0x01 ); // marker
|
|||
bits_write( &bits, 15, i_pts >> 15 ); |
|||
bits_write( &bits, 1, 0x01 ); // marker
|
|||
bits_write( &bits, 15, i_pts ); |
|||
bits_write( &bits, 1, 0x01 ); // marker
|
|||
|
|||
/* write i_dts */ |
|||
if( i_pts_dts & 0x01 ) |
|||
{ |
|||
bits_write( &bits, 4, 0x01 ); // '0001'
|
|||
bits_write( &bits, 3, i_dts >> 30 ); |
|||
bits_write( &bits, 1, 0x01 ); // marker
|
|||
bits_write( &bits, 15, i_dts >> 15 ); |
|||
bits_write( &bits, 1, 0x01 ); // marker
|
|||
bits_write( &bits, 15, i_dts ); |
|||
bits_write( &bits, 1, 0x01 ); // marker
|
|||
|
|||
i_dts = 0; // write dts only once
|
|||
} |
|||
|
|||
} |
|||
else |
|||
{ |
|||
msg_Warn( p_sout, "es isn't mpeg2 -->corrupted pes" ); |
|||
} |
|||
/* now should be stuffing */ |
|||
/* and then pes data */ |
|||
|
|||
bits_align( &bits ); |
|||
break; |
|||
} |
|||
|
|||
if( i_copy > 0 ) |
|||
{ |
|||
memcpy( p_pes->p_buffer + bits.i_data, p_data, i_copy ); |
|||
} |
|||
|
|||
i_size -= i_copy; |
|||
p_data += i_copy; |
|||
p_pes->i_size = bits.i_data + i_copy; |
|||
|
|||
|
|||
} while( i_size > 0 ); |
|||
|
|||
sout_BufferDelete( p_sout, p_es ); |
|||
return( 0 ); |
|||
} |
|||
|
|||
@ -0,0 +1,38 @@ |
|||
/*****************************************************************************
|
|||
* pes.h |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: pes.h,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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. |
|||
*****************************************************************************/ |
|||
|
|||
|
|||
#define PES_PROGRAM_STREAM_MAP 0xbc |
|||
#define PES_PADDING 0xbe |
|||
#define PES_PRIVATE_STREAM_2 0xbf |
|||
#define PES_ECM 0xb0 |
|||
#define PES_EMM 0xb1 |
|||
#define PES_PROGRAM_STREAM_DIRECTORY 0xff |
|||
#define PES_DSMCC_STREAM 0xf2 |
|||
#define PES_ITU_T_H222_1_TYPE_E_STREAM 0xf8 |
|||
|
|||
|
|||
int EStoPES( sout_instance_t *p_sout, |
|||
sout_buffer_t **pp_pes, sout_buffer_t *p_es, |
|||
int i_stream_id, int b_mpeg2 ); |
|||
@ -0,0 +1,361 @@ |
|||
/*****************************************************************************
|
|||
* ps.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: ps.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#include "codecs.h" |
|||
#include "bits.h" |
|||
#include "pes.h" |
|||
|
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static int Open ( vlc_object_t * ); |
|||
static void Close ( vlc_object_t * ); |
|||
|
|||
static int AddStream( sout_instance_t *, sout_input_t * ); |
|||
static int DelStream( sout_instance_t *, sout_input_t * ); |
|||
static int Mux ( sout_instance_t * ); |
|||
|
|||
static void SetWBE ( uint8_t *p, uint16_t v ) |
|||
{ |
|||
p[0] = ( v >> 8 )&0xff; |
|||
p[1] = v&0xff; |
|||
} |
|||
static void SetDWBE( uint8_t *p, uint32_t v ) |
|||
{ |
|||
SetWBE( p, ( v >> 16 )&0xffff ); |
|||
SetWBE( p + 2, v & 0xffff ); |
|||
} |
|||
#define ADD_DWBE( p_buff, v ) \ |
|||
SetDWBE( (p_buff)->p_buffer + i_buffer, (v) ); \ |
|||
i_buffer +=4; |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
vlc_module_begin(); |
|||
set_description( _("PS muxer") ); |
|||
set_capability( "sout mux", 50 ); |
|||
add_shortcut( "ps" ); |
|||
set_callbacks( Open, Close ); |
|||
vlc_module_end(); |
|||
|
|||
typedef struct ps_stream_s |
|||
{ |
|||
int i_ok; |
|||
|
|||
int i_stream_id; |
|||
|
|||
} ps_stream_t; |
|||
|
|||
typedef struct sout_mux_s |
|||
{ |
|||
|
|||
int i_stream_id_mpga; |
|||
int i_stream_id_mpgv; |
|||
int i_stream_id_a52; |
|||
|
|||
int i_audio_bound; |
|||
int i_video_bound; |
|||
|
|||
int i_pes_count; |
|||
|
|||
int i_system_header; |
|||
} sout_mux_t; |
|||
|
|||
/*****************************************************************************
|
|||
* Open: |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_mux_t *p_mux; |
|||
|
|||
msg_Info( p_sout, "Open" ); |
|||
|
|||
p_mux = malloc( sizeof( sout_mux_t ) ); |
|||
|
|||
p_sout->pf_mux_addstream = AddStream; |
|||
p_sout->pf_mux_delstream = DelStream; |
|||
p_sout->pf_mux = Mux; |
|||
p_sout->p_mux_data = (void*)p_mux; |
|||
|
|||
p_mux->i_stream_id_mpga = 0xc0; |
|||
p_mux->i_stream_id_a52 = 0x80; |
|||
p_mux->i_stream_id_mpgv = 0xe0; |
|||
p_mux->i_audio_bound = 0; |
|||
p_mux->i_video_bound = 0; |
|||
p_mux->i_system_header = 0; |
|||
p_mux->i_pes_count = 0; |
|||
|
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Close: |
|||
*****************************************************************************/ |
|||
|
|||
static void Close( vlc_object_t * p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
sout_buffer_t *p_end; |
|||
|
|||
msg_Info( p_sout, "Close" ); |
|||
|
|||
p_end = sout_BufferNew( p_sout, 4 ); |
|||
SetDWBE( p_end->p_buffer, 0x01b9 ); |
|||
|
|||
p_sout->pf_write( p_sout, p_end ); |
|||
|
|||
free( p_mux ); |
|||
|
|||
p_sout->p_mux_data = NULL; |
|||
} |
|||
|
|||
|
|||
static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
ps_stream_t *p_stream; |
|||
|
|||
msg_Dbg( p_sout, "adding input", p_sout ); |
|||
p_input->p_mux_data = (void*)p_stream = malloc( sizeof( ps_stream_t ) ); |
|||
p_stream->i_ok = 0; |
|||
switch( p_input->input_format.i_cat ) |
|||
{ |
|||
case VIDEO_ES: |
|||
p_stream->i_stream_id = p_mux->i_stream_id_mpgv; |
|||
p_mux->i_stream_id_mpgv++; |
|||
p_mux->i_video_bound++; |
|||
break; |
|||
case AUDIO_ES: |
|||
if( p_input->input_format.i_fourcc == VLC_FOURCC( 'a', '5', '2', ' ' ) ) |
|||
{ |
|||
p_stream->i_stream_id = p_mux->i_stream_id_a52; |
|||
p_mux->i_stream_id_a52++; |
|||
} |
|||
else |
|||
{ |
|||
p_stream->i_stream_id = p_mux->i_stream_id_mpga; |
|||
p_mux->i_stream_id_mpga++; |
|||
} |
|||
p_mux->i_audio_bound++; |
|||
break; |
|||
default: |
|||
return( -1 ); |
|||
} |
|||
|
|||
p_stream->i_ok = 1; |
|||
msg_Dbg( p_sout, "adding input stream_id:0x%x [OK]", p_stream->i_stream_id, p_sout ); |
|||
return( 0 ); |
|||
} |
|||
|
|||
static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input ) |
|||
{ |
|||
ps_stream_t *p_stream =(ps_stream_t*)p_input->p_mux_data; |
|||
|
|||
msg_Dbg( p_sout, "removing input" ); |
|||
if( p_stream ) |
|||
{ |
|||
free( p_stream ); |
|||
} |
|||
return( 0 ); |
|||
} |
|||
|
|||
static int MuxWritePackHeader( sout_instance_t *p_sout, |
|||
mtime_t i_dts ) |
|||
{ |
|||
sout_buffer_t *p_hdr; |
|||
bits_buffer_t bits; |
|||
mtime_t i_src; |
|||
|
|||
i_src = i_dts * 9 / 100; |
|||
|
|||
p_hdr = sout_BufferNew( p_sout, 18 ); |
|||
bits_initwrite( &bits, 14, p_hdr->p_buffer ); |
|||
bits_write( &bits, 32, 0x01ba ); |
|||
bits_write( &bits, 2, 0x01 ); // FIXME ??
|
|||
bits_write( &bits, 3, ( i_src >> 30 )&0x07 ); |
|||
bits_write( &bits, 1, 1 ); |
|||
bits_write( &bits, 15, ( i_src >> 15 )&0x7fff ); |
|||
bits_write( &bits, 1, 1 ); |
|||
bits_write( &bits, 15, i_src&0x7fff ); |
|||
bits_write( &bits, 1, 1 ); |
|||
|
|||
bits_write( &bits, 9, 0 ); // src extention
|
|||
bits_write( &bits, 1, 1 ); |
|||
|
|||
bits_write( &bits, 22, 0/8/50); // FIXME
|
|||
bits_write( &bits, 1, 1 ); |
|||
bits_write( &bits, 1, 1 ); |
|||
bits_write( &bits, 5, 0x1f ); // FIXME reserved
|
|||
bits_write( &bits, 3, 0 ); // stuffing bytes
|
|||
p_hdr->i_size = 14; |
|||
p_sout->pf_write( p_sout, p_hdr ); |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
static int MuxWriteSystemHeader( sout_instance_t *p_sout ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
sout_buffer_t *p_hdr; |
|||
bits_buffer_t bits; |
|||
|
|||
p_hdr = sout_BufferNew( p_sout, 12 ); |
|||
|
|||
bits_initwrite( &bits, 12, p_hdr->p_buffer ); |
|||
bits_write( &bits, 32, 0x01bb ); |
|||
bits_write( &bits, 16, 12 - 6); |
|||
bits_write( &bits, 1, 1 ); |
|||
bits_write( &bits, 22, 0 ); // FIXME rate bound
|
|||
bits_write( &bits, 1, 1 ); |
|||
|
|||
bits_write( &bits, 6, p_mux->i_audio_bound ); |
|||
bits_write( &bits, 1, 0 ); // fixed flag
|
|||
bits_write( &bits, 1, 0 ); // CSPS flag
|
|||
bits_write( &bits, 1, 0 ); // system audio lock flag
|
|||
bits_write( &bits, 1, 0 ); // system video lock flag
|
|||
|
|||
bits_write( &bits, 1, 1 ); // marker bit
|
|||
|
|||
bits_write( &bits, 5, p_mux->i_video_bound ); |
|||
bits_write( &bits, 1, 0 ); // packet rate restriction flag
|
|||
bits_write( &bits, 7, 0x7f ); // reserved bits
|
|||
|
|||
/* FIXME missing stream_id ... */ |
|||
|
|||
p_sout->pf_write( p_sout, p_hdr ); |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
/* return stream number to be muxed */ |
|||
static int MuxGetStream( sout_instance_t *p_sout, |
|||
int *pi_stream, |
|||
mtime_t *pi_dts ) |
|||
{ |
|||
mtime_t i_dts; |
|||
int i_stream; |
|||
int i; |
|||
|
|||
for( i = 0, i_dts = 0, i_stream = -1; i < p_sout->i_nb_inputs; i++ ) |
|||
{ |
|||
sout_fifo_t *p_fifo; |
|||
|
|||
p_fifo = p_sout->pp_inputs[i]->p_fifo; |
|||
|
|||
if( p_fifo->i_depth > 1 ) |
|||
{ |
|||
sout_buffer_t *p_buf; |
|||
|
|||
p_buf = sout_FifoShow( p_fifo ); |
|||
if( i_stream < 0 || p_buf->i_dts < i_dts ) |
|||
{ |
|||
i_dts = p_buf->i_dts; |
|||
i_stream = i; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
return( -1 ); // wait that all fifo have at least 2 packets
|
|||
} |
|||
} |
|||
|
|||
if( pi_stream ) |
|||
{ |
|||
*pi_stream = i_stream; |
|||
} |
|||
if( pi_dts ) |
|||
{ |
|||
*pi_dts = i_dts; |
|||
} |
|||
|
|||
return( i_stream ); |
|||
} |
|||
|
|||
|
|||
static int Mux ( sout_instance_t *p_sout ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
mtime_t i_dts; |
|||
int i_stream; |
|||
|
|||
for( ;; ) |
|||
{ |
|||
sout_input_t *p_input; |
|||
ps_stream_t *p_stream; |
|||
sout_fifo_t *p_fifo; |
|||
sout_buffer_t *p_data; |
|||
|
|||
if( MuxGetStream( p_sout, &i_stream, &i_dts ) < 0 ) |
|||
{ |
|||
return( 0 ); |
|||
} |
|||
|
|||
p_input = p_sout->pp_inputs[i_stream]; |
|||
p_fifo = p_input->p_fifo; |
|||
p_stream = (ps_stream_t*)p_input->p_mux_data; |
|||
|
|||
if( p_mux->i_pes_count % 30 == 0) |
|||
{ |
|||
MuxWritePackHeader( p_sout, i_dts ); |
|||
} |
|||
|
|||
if( p_mux->i_pes_count % 300 == 0 ) |
|||
{ |
|||
// MuxWriteSystemHeader( p_sout );
|
|||
} |
|||
|
|||
p_data = sout_FifoGet( p_fifo ); |
|||
EStoPES( p_sout, &p_data, p_data, p_stream->i_stream_id, 1); |
|||
p_sout->pf_write( p_sout, p_data ); |
|||
|
|||
p_mux->i_pes_count++; |
|||
|
|||
} |
|||
return( 0 ); |
|||
} |
|||
|
|||
@ -0,0 +1,599 @@ |
|||
/*****************************************************************************
|
|||
* ts.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: ts.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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 <stdlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <string.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE ) |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#include "codecs.h" |
|||
#include "bits.h" |
|||
#include "pes.h" |
|||
|
|||
typedef struct ts_stream_s |
|||
{ |
|||
int i_pid; |
|||
int i_stream_type; |
|||
int i_stream_id; |
|||
int i_continuity_counter; |
|||
} ts_stream_t; |
|||
|
|||
typedef struct sout_mux_s |
|||
{ |
|||
int i_pcr_pid; |
|||
int i_stream_id_mpga; |
|||
int i_stream_id_mpgv; |
|||
int i_stream_id_a52; |
|||
|
|||
int i_audio_bound; |
|||
int i_video_bound; |
|||
|
|||
int i_pid_free; // first usable pid
|
|||
|
|||
int i_pat_version_number; |
|||
ts_stream_t pat; |
|||
|
|||
int i_pmt_version_number; |
|||
ts_stream_t pmt; // Up to now only one program
|
|||
|
|||
int i_ts_packet;// To known when to put pat/mpt
|
|||
} sout_mux_t; |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static int Open ( vlc_object_t * ); |
|||
static void Close ( vlc_object_t * ); |
|||
|
|||
static int AddStream( sout_instance_t *, sout_input_t * ); |
|||
static int DelStream( sout_instance_t *, sout_input_t * ); |
|||
static int Mux ( sout_instance_t * ); |
|||
|
|||
/* Reserve a pid and return it */ |
|||
static int AllocatePID( sout_mux_t *p_mux ) |
|||
{ |
|||
return( ++p_mux->i_pid_free ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
vlc_module_begin(); |
|||
set_description( _("TS muxer") ); |
|||
set_capability( "sout mux", 100 ); |
|||
add_shortcut( "ts" ); |
|||
set_callbacks( Open, Close ); |
|||
vlc_module_end(); |
|||
|
|||
/*****************************************************************************
|
|||
* Open: |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_mux_t *p_mux; |
|||
|
|||
msg_Info( p_sout, "Open" ); |
|||
|
|||
p_mux = malloc( sizeof( sout_mux_t ) ); |
|||
|
|||
p_sout->pf_mux_addstream = AddStream; |
|||
p_sout->pf_mux_delstream = DelStream; |
|||
p_sout->pf_mux = Mux; |
|||
p_sout->p_mux_data = (void*)p_mux; |
|||
|
|||
p_mux->i_stream_id_mpga = 0xc0; |
|||
p_mux->i_stream_id_a52 = 0x80; |
|||
p_mux->i_stream_id_mpgv = 0xe0; |
|||
|
|||
p_mux->i_audio_bound = 0; |
|||
p_mux->i_video_bound = 0; |
|||
|
|||
p_mux->i_pat_version_number = 0; |
|||
p_mux->pat.i_pid = 0; |
|||
p_mux->pat.i_continuity_counter = 0; |
|||
|
|||
p_mux->i_pmt_version_number = 0; |
|||
p_mux->pmt.i_pid = 0x10; |
|||
p_mux->pmt.i_continuity_counter = 0; |
|||
|
|||
p_mux->i_pid_free = 0x11; |
|||
p_mux->i_pcr_pid = 0x1fff; |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Close: |
|||
*****************************************************************************/ |
|||
|
|||
static void Close( vlc_object_t * p_this ) |
|||
{ |
|||
sout_instance_t *p_sout = (sout_instance_t*)p_this; |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
|
|||
msg_Info( p_sout, "Close" ); |
|||
|
|||
free( p_mux ); |
|||
p_sout->p_mux_data = NULL; |
|||
} |
|||
|
|||
|
|||
static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
ts_stream_t *p_stream; |
|||
|
|||
msg_Dbg( p_sout, "adding input" ); |
|||
p_input->p_mux_data = (void*)p_stream = malloc( sizeof( ts_stream_t ) ); |
|||
|
|||
p_stream->i_pid = AllocatePID( p_mux ); |
|||
if( p_mux->i_pcr_pid == 0x1fff ) |
|||
{ |
|||
p_mux->i_pcr_pid = p_stream->i_pid; |
|||
} |
|||
p_stream->i_continuity_counter = 0; |
|||
|
|||
switch( p_input->input_format.i_cat ) |
|||
{ |
|||
case VIDEO_ES: |
|||
switch( p_input->input_format.i_fourcc ) |
|||
{ |
|||
case VLC_FOURCC( 'm', 'p','g', 'v' ): |
|||
p_stream->i_stream_type = 0x02; |
|||
p_stream->i_stream_id = p_mux->i_stream_id_mpgv; |
|||
p_mux->i_stream_id_mpgv++; |
|||
break; |
|||
case VLC_FOURCC( 'm', 'p','4', 'v' ): |
|||
p_stream->i_stream_type = 0x10; |
|||
p_stream->i_stream_id = 0xfa; |
|||
break; |
|||
default: |
|||
return( -1 ); |
|||
} |
|||
p_mux->i_video_bound++; |
|||
|
|||
break; |
|||
case AUDIO_ES: |
|||
switch( p_input->input_format.i_fourcc ) |
|||
{ |
|||
case VLC_FOURCC( 'a', '5','2', ' ' ): |
|||
case VLC_FOURCC( 'a', '5','2', 'b' ): |
|||
p_stream->i_stream_type = 0x81; |
|||
p_stream->i_stream_id = p_mux->i_stream_id_a52; |
|||
p_mux->i_stream_id_a52++; |
|||
break; |
|||
#if 0 |
|||
case VLC_FOURCC( 'm', 'p','4', 'a' ): |
|||
p_stream->i_stream_type = 0x11; |
|||
p_stream->i_stream_id = 0xfa; |
|||
p_mux->i_stream_id_mp4a++; |
|||
break; |
|||
#endif |
|||
case VLC_FOURCC( 'm', 'p','g', 'a' ): |
|||
p_stream->i_stream_type = 0x04; |
|||
p_stream->i_stream_id = p_mux->i_stream_id_mpga; |
|||
p_mux->i_stream_id_mpga++; |
|||
break; |
|||
default: |
|||
return( -1 ); |
|||
} |
|||
p_mux->i_audio_bound++; |
|||
break; |
|||
default: |
|||
return( -1 ); |
|||
} |
|||
|
|||
p_mux->i_ts_packet = 0; // force pat/pmt recreation
|
|||
p_mux->i_pat_version_number++; p_mux->i_pat_version_number %= 32; |
|||
p_mux->i_pmt_version_number++; p_mux->i_pmt_version_number %= 32; |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
|
|||
msg_Dbg( p_sout, "removing input" ); |
|||
p_mux->i_ts_packet = 0; // force pat/pmt recreation
|
|||
p_mux->i_pat_version_number++; p_mux->i_pat_version_number %= 32; |
|||
p_mux->i_pmt_version_number++; p_mux->i_pmt_version_number %= 32; |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
|
|||
static int MuxGetStream( sout_instance_t *p_sout, |
|||
int *pi_stream, |
|||
mtime_t *pi_dts ) |
|||
{ |
|||
mtime_t i_dts; |
|||
int i_stream; |
|||
int i; |
|||
|
|||
for( i = 0, i_dts = 0, i_stream = -1; i < p_sout->i_nb_inputs; i++ ) |
|||
{ |
|||
sout_fifo_t *p_fifo; |
|||
|
|||
p_fifo = p_sout->pp_inputs[i]->p_fifo; |
|||
|
|||
if( p_fifo->i_depth > 1 ) |
|||
{ |
|||
sout_buffer_t *p_buf; |
|||
|
|||
p_buf = sout_FifoShow( p_fifo ); |
|||
if( i_stream < 0 || p_buf->i_dts < i_dts ) |
|||
{ |
|||
i_dts = p_buf->i_dts; |
|||
i_stream = i; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
return( -1 ); // wait that all fifo have at least 2 packets
|
|||
} |
|||
} |
|||
|
|||
if( pi_stream ) |
|||
{ |
|||
*pi_stream = i_stream; |
|||
} |
|||
if( pi_dts ) |
|||
{ |
|||
*pi_dts = i_dts; |
|||
} |
|||
|
|||
return( i_stream ); |
|||
} |
|||
|
|||
static int PEStoTS( sout_instance_t *p_sout, |
|||
sout_buffer_t **pp_ts, sout_buffer_t *p_pes, |
|||
ts_stream_t *p_stream ) |
|||
{ |
|||
int i_size; |
|||
sout_buffer_t *p_last_buffer = NULL; |
|||
uint8_t *p_data; |
|||
int i_first; |
|||
mtime_t i_dts; |
|||
int b_new_pes; |
|||
/* get PES total size */ |
|||
i_size = p_pes->i_size; |
|||
p_data = p_pes->p_buffer; |
|||
|
|||
if( p_pes->i_dts == 0 && p_pes->i_length > 0 ) |
|||
{ |
|||
i_dts = 1; // XXX <french> kludge immonde </french>
|
|||
} |
|||
else |
|||
{ |
|||
i_dts = p_pes->i_dts; |
|||
} |
|||
|
|||
for( i_first = 1, b_new_pes = 1; p_pes != NULL; ) |
|||
{ |
|||
int i_adaptation_field; |
|||
int i_payload; |
|||
int i_copy; |
|||
bits_buffer_t bits; |
|||
sout_buffer_t *p_ts; |
|||
|
|||
p_ts = sout_BufferNew( p_sout, 188 ); |
|||
|
|||
p_ts->i_pts = 0; |
|||
p_ts->i_dts = i_dts; |
|||
|
|||
|
|||
i_payload = 184 - ( i_first && i_dts > 0 ? 8 : 0 ); |
|||
i_copy = __MIN( i_size, i_payload ); |
|||
|
|||
i_adaptation_field = ( ( i_first && i_dts > 0 ) || |
|||
i_size < i_payload ) ? 1 : 0; |
|||
|
|||
/* write headers */ |
|||
bits_initwrite( &bits, 188, p_ts->p_buffer ); |
|||
bits_write( &bits, 8, 0x47 ); /* sync byte */ |
|||
bits_write( &bits, 1, 0 ); /* transport_error_indicator */ |
|||
bits_write( &bits, 1, b_new_pes ? 1 : 0 ); /* payload_unit_start */ |
|||
b_new_pes = 0; |
|||
bits_write( &bits, 1, 0 ); /* transport_priority */ |
|||
bits_write( &bits, 13, p_stream->i_pid ); |
|||
bits_write( &bits, 2, 0 ); /* transport_scrambling_control */ |
|||
bits_write( &bits, 2, ( i_adaptation_field ? 0x03 : 0x01 ) ); |
|||
|
|||
bits_write( &bits, 4, /* continuity_counter */ |
|||
p_stream->i_continuity_counter ); |
|||
p_stream->i_continuity_counter++; |
|||
p_stream->i_continuity_counter %= 16; |
|||
if( i_adaptation_field ) |
|||
{ |
|||
int i; |
|||
int i_stuffing; |
|||
|
|||
if( i_first && i_dts > 0 ) |
|||
{ |
|||
i_stuffing = i_payload - i_copy; |
|||
bits_write( &bits, 8, 7 + i_stuffing ); |
|||
bits_write( &bits, 8, 0x10 ); /* various flags */ |
|||
bits_write( &bits, 33, i_dts * 9 / 100); |
|||
bits_write( &bits, 6, 0 ); |
|||
bits_write( &bits, 9, 0 ); |
|||
i_dts = 0; /* XXX set dts only for first ts packet */ |
|||
} |
|||
else |
|||
{ |
|||
i_stuffing = i_payload - i_copy; |
|||
bits_write( &bits, 8, i_stuffing - 1); |
|||
if( i_stuffing - 1 > 0 ) |
|||
{ |
|||
bits_write( &bits, 8, 0 ); |
|||
} |
|||
i_stuffing -= 2; |
|||
} |
|||
|
|||
/* put stuffing */ |
|||
for( i = 0; i < i_stuffing; i++ ) |
|||
{ |
|||
bits_write( &bits, 8, 0xff ); |
|||
} |
|||
} |
|||
/* copy payload */ |
|||
memcpy( p_ts->p_buffer + bits.i_data, |
|||
p_data, |
|||
i_copy ); |
|||
p_data += i_copy; |
|||
i_size -= i_copy; |
|||
|
|||
/* chain buffers */ |
|||
if( i_first ) |
|||
{ |
|||
*pp_ts = p_ts; |
|||
p_last_buffer = p_ts; |
|||
} |
|||
else |
|||
{ |
|||
p_last_buffer->p_next = p_ts; |
|||
p_last_buffer = p_ts; |
|||
} |
|||
i_first = 0; |
|||
|
|||
if( i_size <= 0 ) |
|||
{ |
|||
sout_buffer_t *p_next; |
|||
|
|||
p_next = p_pes->p_next; |
|||
p_pes->p_next = NULL; |
|||
sout_BufferDelete( p_sout, p_pes ); |
|||
p_pes = p_next; |
|||
b_new_pes = 1; |
|||
if( p_pes ) |
|||
{ |
|||
i_size = p_pes->i_size; |
|||
p_data = p_pes->p_buffer; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int GetPAT( sout_instance_t *p_sout, |
|||
sout_buffer_t **pp_ts ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
sout_buffer_t *p_pat; |
|||
bits_buffer_t bits; |
|||
|
|||
p_pat = sout_BufferNew( p_sout, 1024 ); |
|||
|
|||
p_pat->i_pts = 0; |
|||
p_pat->i_dts = 0; |
|||
p_pat->i_length = 0; |
|||
|
|||
bits_initwrite( &bits, 1024, p_pat->p_buffer ); |
|||
|
|||
bits_write( &bits, 8, 0 ); // pointer
|
|||
bits_write( &bits, 8, 0x00 ); // table id
|
|||
bits_write( &bits, 1, 1 ); // section_syntax_indicator
|
|||
bits_write( &bits, 1, 0 ); // 0
|
|||
bits_write( &bits, 2, 0 ); // reserved FIXME
|
|||
bits_write( &bits, 12, 13 ); // XXX for one program only XXX
|
|||
bits_write( &bits, 16, 0x01 ); // FIXME stream id
|
|||
bits_write( &bits, 2, 0 ); // FIXME
|
|||
bits_write( &bits, 5, p_mux->i_pat_version_number ); |
|||
bits_write( &bits, 1, 1 ); // current_next_indicator
|
|||
bits_write( &bits, 8, 0 ); // section number
|
|||
bits_write( &bits, 8, 0 ); // last section number
|
|||
|
|||
bits_write( &bits, 16, 1 ); // program number
|
|||
bits_write( &bits, 3, 0 ); // reserved
|
|||
bits_write( &bits, 13, p_mux->pmt.i_pid ); // program map pid
|
|||
|
|||
bits_write( &bits, 32, 0 ); // FIXME FIXME FIXME
|
|||
|
|||
p_pat->i_size = bits.i_data; |
|||
|
|||
return( PEStoTS( p_sout, pp_ts, p_pat, &p_mux->pat ) ); |
|||
} |
|||
|
|||
static int GetPMT( sout_instance_t *p_sout, |
|||
sout_buffer_t **pp_ts ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
sout_buffer_t *p_pmt; |
|||
bits_buffer_t bits; |
|||
int i_stream; |
|||
|
|||
p_pmt = sout_BufferNew( p_sout, 1024 ); |
|||
|
|||
p_pmt->i_pts = 0; |
|||
p_pmt->i_dts = 0; |
|||
p_pmt->i_length = 0; |
|||
|
|||
bits_initwrite( &bits, 1024, p_pmt->p_buffer ); |
|||
|
|||
bits_write( &bits, 8, 0 ); // pointer
|
|||
bits_write( &bits, 8, 0x02 ); // table id
|
|||
bits_write( &bits, 1, 1 ); // section_syntax_indicator
|
|||
bits_write( &bits, 1, 0 ); // 0
|
|||
bits_write( &bits, 2, 0 ); // reserved FIXME
|
|||
bits_write( &bits, 12, 13 + 5 * p_sout->i_nb_inputs ); |
|||
bits_write( &bits, 16, 1 ); // FIXME program number
|
|||
bits_write( &bits, 2, 0 ); // FIXME
|
|||
bits_write( &bits, 5, p_mux->i_pmt_version_number ); |
|||
bits_write( &bits, 1, 1 ); // current_next_indicator
|
|||
bits_write( &bits, 8, 0 ); // section number
|
|||
bits_write( &bits, 8, 0 ); // last section number
|
|||
|
|||
bits_write( &bits, 3, 0 ); // reserved
|
|||
|
|||
bits_write( &bits, 13, p_mux->i_pcr_pid ); // FIXME FXIME PCR_PID FIXME
|
|||
bits_write( &bits, 4, 0 ); // reserved FIXME
|
|||
|
|||
bits_write( &bits, 12, 0 ); // program info len FIXME
|
|||
|
|||
for( i_stream = 0; i_stream < p_sout->i_nb_inputs; i_stream++ ) |
|||
{ |
|||
ts_stream_t *p_stream; |
|||
|
|||
p_stream = (ts_stream_t*)p_sout->pp_inputs[i_stream]->p_mux_data; |
|||
|
|||
bits_write( &bits, 8, p_stream->i_stream_type ); // stream_type
|
|||
bits_write( &bits, 3, 0 ); // reserved
|
|||
bits_write( &bits, 13, p_stream->i_pid ); // es pid
|
|||
bits_write( &bits, 4, 0 ); //reserved
|
|||
bits_write( &bits, 12, 0 ); // es info len FIXME
|
|||
} |
|||
|
|||
bits_write( &bits, 32, 0 ); // FIXME FIXME FIXME
|
|||
|
|||
p_pmt->i_size = bits.i_data; |
|||
|
|||
return( PEStoTS( p_sout, pp_ts, p_pmt, &p_mux->pmt ) ); |
|||
|
|||
} |
|||
|
|||
static void SetTSDate( sout_buffer_t *p_ts, mtime_t i_dts, mtime_t i_length ) |
|||
{ |
|||
int i_count; |
|||
sout_buffer_t *p_tmp; |
|||
mtime_t i_delta; |
|||
|
|||
for( p_tmp = p_ts, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next ) |
|||
{ |
|||
i_count++; |
|||
} |
|||
i_delta = i_length / i_count; |
|||
|
|||
for( p_tmp = p_ts; p_tmp != NULL; p_tmp = p_tmp->p_next ) |
|||
{ |
|||
p_tmp->i_dts = i_dts; |
|||
p_tmp->i_length = i_delta; |
|||
|
|||
i_dts += i_delta; |
|||
} |
|||
} |
|||
|
|||
static int Mux( sout_instance_t *p_sout ) |
|||
{ |
|||
sout_mux_t *p_mux = (sout_mux_t*)p_sout->p_mux_data; |
|||
mtime_t i_dts; |
|||
int i_stream; |
|||
|
|||
sout_buffer_t *p_pat, *p_pmt, *p_ts; |
|||
|
|||
for( ;; ) |
|||
{ |
|||
mtime_t i_dts, i_length; |
|||
|
|||
sout_input_t *p_input; |
|||
ts_stream_t *p_stream; |
|||
sout_fifo_t *p_fifo; |
|||
sout_buffer_t *p_data; |
|||
|
|||
if( MuxGetStream( p_sout, &i_stream, &i_dts ) < 0 ) |
|||
{ |
|||
return( 0 ); |
|||
} |
|||
|
|||
p_input = p_sout->pp_inputs[i_stream]; |
|||
p_fifo = p_input->p_fifo; |
|||
p_stream = (ts_stream_t*)p_input->p_mux_data; |
|||
|
|||
p_data = sout_FifoGet( p_fifo ); |
|||
i_dts = p_data->i_dts; |
|||
i_length = p_data->i_length; |
|||
|
|||
EStoPES( p_sout, &p_data, p_data, p_stream->i_stream_id, 1); |
|||
PEStoTS( p_sout, &p_data, p_data, p_stream ); |
|||
|
|||
if( p_mux->i_ts_packet % 30 == 0 ) |
|||
{ |
|||
/* create pat/pmt */ |
|||
GetPAT( p_sout, &p_pat ); |
|||
GetPMT( p_sout, &p_pmt ); |
|||
|
|||
p_ts = p_pat; |
|||
p_pat->p_next = p_pmt; |
|||
p_pmt->p_next = p_data; |
|||
} |
|||
else |
|||
{ |
|||
p_pat = NULL; |
|||
p_pmt = NULL; |
|||
p_ts = p_data; |
|||
} |
|||
|
|||
p_mux->i_ts_packet++; |
|||
|
|||
SetTSDate( p_ts, i_dts, i_length ); |
|||
|
|||
p_sout->pf_write( p_sout, p_ts ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,2 @@ |
|||
.deps |
|||
.dirstamp |
|||
@ -0,0 +1,5 @@ |
|||
SOURCES_packetizer_copy = modules/packetizer/copy.c |
|||
SOURCES_packetizer_a52 = modules/packetizer/a52.c |
|||
SOURCES_packetizer_mpegaudio = modules/packetizer/mpegaudio.c |
|||
SOURCES_packetizer_mpegvideo = modules/packetizer/mpegvideo.c |
|||
SOURCES_packetizer_mpeg4video = modules/packetizer/mpeg4video.c |
|||
@ -0,0 +1,393 @@ |
|||
/*****************************************************************************
|
|||
* a52.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: a52.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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/aout.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" /* WAVEFORMATEX BITMAPINFOHEADER */ |
|||
/*****************************************************************************
|
|||
* Local prototypes |
|||
*****************************************************************************/ |
|||
typedef struct packetizer_s |
|||
{ |
|||
/* Input properties */ |
|||
decoder_fifo_t *p_fifo; |
|||
bit_stream_t bit_stream; |
|||
|
|||
/* Output properties */ |
|||
sout_input_t *p_sout_input; |
|||
sout_packet_format_t output_format; |
|||
|
|||
uint64_t i_samplescount; |
|||
|
|||
} packetizer_t; |
|||
|
|||
static int Open ( vlc_object_t * ); |
|||
static int Run ( decoder_fifo_t * ); |
|||
|
|||
static int InitThread ( packetizer_t * ); |
|||
static void PacketizeThread ( packetizer_t * ); |
|||
static void EndThread ( packetizer_t * ); |
|||
|
|||
static int SyncInfo( const byte_t *, int *, int *, int * ); |
|||
|
|||
#define FREE( p ) if( p ) free( p ); p = NULL |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
|
|||
vlc_module_begin(); |
|||
set_description( _("A/52 audio packetizer") ); |
|||
set_capability( "packetizer", 10 ); |
|||
set_callbacks( Open, NULL ); |
|||
vlc_module_end(); |
|||
|
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* OpenDecoder: probe the packetizer and return score |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to choose. |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; |
|||
|
|||
if( p_fifo->i_fourcc != VLC_FOURCC( 'a', '5', '2', ' ') && |
|||
p_fifo->i_fourcc != VLC_FOURCC( 'a', '5', '2', 'b') ) |
|||
{ |
|||
return VLC_EGENERIC; |
|||
} |
|||
|
|||
p_fifo->pf_run = Run; |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* RunDecoder: this function is called just after the thread is created |
|||
*****************************************************************************/ |
|||
static int Run( decoder_fifo_t *p_fifo ) |
|||
{ |
|||
packetizer_t *p_pack; |
|||
int b_error; |
|||
|
|||
msg_Info( p_fifo, "Running A/52 packetizer" ); |
|||
if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) ) |
|||
{ |
|||
msg_Err( p_fifo, "out of memory" ); |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
memset( p_pack, 0, sizeof( packetizer_t ) ); |
|||
|
|||
p_pack->p_fifo = p_fifo; |
|||
|
|||
if( InitThread( p_pack ) != 0 ) |
|||
{ |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
PacketizeThread( p_pack ); |
|||
} |
|||
|
|||
|
|||
if( ( b_error = p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
DecoderError( p_pack->p_fifo ); |
|||
} |
|||
|
|||
EndThread( p_pack ); |
|||
|
|||
FREE( p_pack ); |
|||
|
|||
if( b_error ) |
|||
{ |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* InitThread: initialize data before entering main loop |
|||
*****************************************************************************/ |
|||
|
|||
static int InitThread( packetizer_t *p_pack ) |
|||
{ |
|||
|
|||
p_pack->output_format.i_cat = AUDIO_ES; |
|||
p_pack->output_format.i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' ); |
|||
|
|||
p_pack->output_format.p_format = NULL; |
|||
|
|||
p_pack->p_sout_input = NULL; |
|||
|
|||
p_pack->i_samplescount = 0; |
|||
|
|||
if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo, |
|||
NULL, NULL ) != VLC_SUCCESS ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, "cannot initialize bitstream" ); |
|||
return -1; |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* PacketizeThread: packetize an unit (here copy a complete pes) |
|||
*****************************************************************************/ |
|||
static void PacketizeThread( packetizer_t *p_pack ) |
|||
{ |
|||
sout_buffer_t *p_sout_buffer; |
|||
|
|||
|
|||
uint8_t p_header[7]; |
|||
int i_channels, i_samplerate, i_bitrate; |
|||
int i_framelength; |
|||
|
|||
/* search a valid start code */ |
|||
for( ;; ) |
|||
{ |
|||
int i_skip = 0; |
|||
|
|||
RealignBits( &p_pack->bit_stream ); |
|||
while( ShowBits( &p_pack->bit_stream, 16 ) != 0x0b77 && |
|||
!p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error ) |
|||
{ |
|||
RemoveBits( &p_pack->bit_stream, 8 ); |
|||
i_skip++; |
|||
} |
|||
if( i_skip ) |
|||
{ |
|||
msg_Warn( p_pack->p_fifo, "trashing %d bytes", i_skip ); |
|||
} |
|||
if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error ) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
GetChunk( &p_pack->bit_stream, p_header, 7 ); |
|||
if( p_pack->p_fifo->b_die ) return; |
|||
|
|||
/* Check if frame is valid and get frame info */ |
|||
i_framelength = SyncInfo( p_header, &i_channels, &i_samplerate, |
|||
&i_bitrate ); |
|||
|
|||
if( !i_framelength ) |
|||
{ |
|||
msg_Warn( p_pack->p_fifo, "invalid header found" ); |
|||
continue; |
|||
} |
|||
else |
|||
{ |
|||
// msg_Dbg( p_pack->p_fifo, "frame length %d b", i_framelength );
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
/* add a input for the stream ouput */ |
|||
WAVEFORMATEX *p_wf; |
|||
|
|||
p_wf = malloc( sizeof( WAVEFORMATEX ) ); |
|||
p_pack->output_format.p_format = (void*)p_wf; |
|||
|
|||
p_wf->wFormatTag = WAVE_FORMAT_A52; |
|||
p_wf->nChannels = i_channels; |
|||
p_wf->nSamplesPerSec = i_samplerate; |
|||
p_wf->nAvgBytesPerSec = 0; |
|||
p_wf->nBlockAlign = 1; |
|||
p_wf->wBitsPerSample = 0; |
|||
p_wf->cbSize = 0; |
|||
|
|||
p_pack->p_sout_input = |
|||
sout_InputNew( p_pack->p_fifo, |
|||
&p_pack->output_format ); |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, |
|||
"cannot add a new stream" ); |
|||
p_pack->p_fifo->b_error = 1; |
|||
return; |
|||
} |
|||
msg_Info( p_pack->p_fifo, |
|||
"A/52 channels:%d samplerate:%d bitrate:%d", |
|||
i_channels, i_samplerate, i_bitrate ); |
|||
} |
|||
|
|||
p_sout_buffer = |
|||
sout_BufferNew( p_pack->p_sout_input->p_sout, i_framelength ); |
|||
if( !p_sout_buffer ) |
|||
{ |
|||
p_pack->p_fifo->b_error = 1; |
|||
return; |
|||
} |
|||
memcpy( p_sout_buffer->p_buffer, p_header, 7 ); |
|||
p_sout_buffer->i_bitrate = i_bitrate; |
|||
|
|||
p_sout_buffer->i_pts = |
|||
p_sout_buffer->i_dts = |
|||
(uint64_t)1000000 * |
|||
(uint64_t)p_pack->i_samplescount / |
|||
(uint64_t)i_samplerate; |
|||
p_sout_buffer->i_length = |
|||
(uint64_t)1000000 * |
|||
(uint64_t)A52_FRAME_NB / |
|||
(uint64_t)i_samplerate; |
|||
|
|||
p_pack->i_samplescount += A52_FRAME_NB; |
|||
|
|||
/* we are already aligned */ |
|||
GetChunk( &p_pack->bit_stream, |
|||
p_sout_buffer->p_buffer + 7, |
|||
i_framelength - 7 ); |
|||
|
|||
sout_InputSendBuffer( p_pack->p_sout_input, |
|||
p_sout_buffer ); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* EndThread : packetizer thread destruction |
|||
*****************************************************************************/ |
|||
static void EndThread ( packetizer_t *p_pack) |
|||
{ |
|||
if( p_pack->p_sout_input ) |
|||
{ |
|||
sout_InputDelete( p_pack->p_sout_input ); |
|||
} |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* SyncInfo: parse A52 sync info |
|||
***************************************************************************** |
|||
* This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse, |
|||
* since we don't want to oblige S/PDIF people to use liba52 just to get |
|||
* their SyncInfo... |
|||
* fenrir: I've change it to report channels count |
|||
*****************************************************************************/ |
|||
static int SyncInfo( const byte_t * p_buf, int * pi_channels, |
|||
int * pi_sample_rate, int * pi_bit_rate ) |
|||
{ |
|||
static const uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 }; |
|||
static const int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, |
|||
128, 160, 192, 224, 256, 320, 384, 448, |
|||
512, 576, 640 }; |
|||
static const uint8_t lfeon[8] = { 0x10, 0x10, 0x04, 0x04, |
|||
0x04, 0x01, 0x04, 0x01 }; |
|||
int frmsizecod; |
|||
int bitrate; |
|||
int half; |
|||
int acmod; |
|||
|
|||
if ((p_buf[0] != 0x0b) || (p_buf[1] != 0x77)) /* syncword */ |
|||
return 0; |
|||
|
|||
if (p_buf[5] >= 0x60) /* bsid >= 12 */ |
|||
return 0; |
|||
half = halfrate[p_buf[5] >> 3]; |
|||
|
|||
/* acmod, dsurmod and lfeon */ |
|||
acmod = p_buf[6] >> 5; |
|||
if ( (p_buf[6] & 0xf8) == 0x50 ) |
|||
{ |
|||
/* Dolby surround = stereo + Dolby */ |
|||
/* *pi_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
|
|||
| AOUT_CHAN_DOLBYSTEREO;*/ |
|||
*pi_channels = 2; /* FIXME ??? */ |
|||
} |
|||
else switch ( acmod ) |
|||
{ |
|||
case 0x0: |
|||
/* Dual-mono = stereo + dual-mono */ |
|||
// *pi_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
|
|||
// | AOUT_CHAN_DUALMONO;
|
|||
*pi_channels = 2; /* FIXME ??? */ |
|||
break; |
|||
case 0x1: |
|||
/* Mono */ |
|||
*pi_channels = 1; |
|||
break; |
|||
case 0x2: |
|||
/* Stereo */ |
|||
*pi_channels = 2; |
|||
break; |
|||
case 0x3: /* 3F */ |
|||
case 0x4: /* 2F1R */ |
|||
*pi_channels = 3; |
|||
break; |
|||
case 0x5: /* 3F1R */ |
|||
case 0x6: /* 2F2R */ |
|||
*pi_channels = 4; |
|||
break; |
|||
case 0x7: |
|||
/* 3F2R */ |
|||
*pi_channels = 5; |
|||
break; |
|||
default: |
|||
return 0; |
|||
} |
|||
|
|||
if ( p_buf[6] & lfeon[acmod] ) *pi_channels += 1;//|= AOUT_CHAN_LFEA;
|
|||
|
|||
frmsizecod = p_buf[4] & 63; |
|||
if (frmsizecod >= 38) |
|||
return 0; |
|||
bitrate = rate [frmsizecod >> 1]; |
|||
*pi_bit_rate = (bitrate * 1000) >> half; |
|||
|
|||
switch (p_buf[4] & 0xc0) { |
|||
case 0: |
|||
*pi_sample_rate = 48000 >> half; |
|||
return 4 * bitrate; |
|||
case 0x40: |
|||
*pi_sample_rate = 44100 >> half; |
|||
return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); |
|||
case 0x80: |
|||
*pi_sample_rate = 32000 >> half; |
|||
return 6 * bitrate; |
|||
default: |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,227 @@ |
|||
/*****************************************************************************
|
|||
* copy.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: copy.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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/aout.h> |
|||
#include <vlc/decoder.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#include <stdlib.h> /* malloc(), free() */ |
|||
#include <string.h> /* strdup() */ |
|||
|
|||
/*****************************************************************************
|
|||
* Local prototypes |
|||
*****************************************************************************/ |
|||
typedef struct packetizer_thread_s |
|||
{ |
|||
/* Input properties */ |
|||
decoder_fifo_t *p_fifo; |
|||
|
|||
/* Output properties */ |
|||
sout_input_t *p_sout_input; |
|||
sout_packet_format_t output_format; |
|||
|
|||
} packetizer_thread_t; |
|||
|
|||
static int Open ( vlc_object_t * ); |
|||
static int Run ( decoder_fifo_t * ); |
|||
|
|||
static int InitThread ( packetizer_thread_t * ); |
|||
static void PacketizeThread ( packetizer_thread_t * ); |
|||
static void EndThread ( packetizer_thread_t * ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
|
|||
vlc_module_begin(); |
|||
set_description( _("Copy packetizer") ); |
|||
set_capability( "packetizer", 0 ); |
|||
set_callbacks( Open, NULL ); |
|||
vlc_module_end(); |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* OpenDecoder: probe the packetizer and return score |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to choose. |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; |
|||
|
|||
p_fifo->pf_run = Run; |
|||
|
|||
return VLC_SUCCESS; |
|||
|
|||
#if 0 |
|||
if( p_fifo->i_fourcc == VLC_FOURCC( 'm', 'p', 'g', 'a') ) |
|||
.... |
|||
#endif |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* RunDecoder: this function is called just after the thread is created |
|||
*****************************************************************************/ |
|||
static int Run( decoder_fifo_t *p_fifo ) |
|||
{ |
|||
packetizer_thread_t *p_pack; |
|||
int b_error; |
|||
|
|||
msg_Info( p_fifo, "Running copy packetizer" ); |
|||
if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) ) |
|||
{ |
|||
msg_Err( p_fifo, "out of memory" ); |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
memset( p_pack, 0, sizeof( packetizer_thread_t ) ); |
|||
|
|||
p_pack->p_fifo = p_fifo; |
|||
|
|||
if( InitThread( p_pack ) != 0 ) |
|||
{ |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
PacketizeThread( p_pack ); |
|||
} |
|||
|
|||
|
|||
if( ( b_error = p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
DecoderError( p_pack->p_fifo ); |
|||
} |
|||
|
|||
EndThread( p_pack ); |
|||
if( b_error ) |
|||
{ |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
#define FREE( p ) if( p ) free( p ); p = NULL |
|||
|
|||
/*****************************************************************************
|
|||
* InitThread: initialize data before entering main loop |
|||
*****************************************************************************/ |
|||
|
|||
static int InitThread( packetizer_thread_t *p_pack ) |
|||
{ |
|||
|
|||
// p_pack->output_format.i_cat = p_pack->p_fifo->i_cat;
|
|||
p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc; |
|||
|
|||
p_pack->p_sout_input = |
|||
sout_InputNew( p_pack->p_fifo, |
|||
&p_pack->output_format ); |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, |
|||
"cannot add a new stream" ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* PacketizeThread: packetize an unit (here copy a complete pes) |
|||
*****************************************************************************/ |
|||
static void PacketizeThread( packetizer_thread_t *p_pack ) |
|||
{ |
|||
sout_buffer_t *p_sout_buffer; |
|||
pes_packet_t *p_pes; |
|||
size_t i_size; |
|||
|
|||
/* **** get samples count **** */ |
|||
input_ExtractPES( p_pack->p_fifo, &p_pes ); |
|||
if( !p_pes ) |
|||
{ |
|||
p_pack->p_fifo->b_error = 1; |
|||
return; |
|||
} |
|||
i_size = p_pes->i_pes_size; |
|||
|
|||
if( i_size > 0 ) |
|||
{ |
|||
data_packet_t *p_data; |
|||
size_t i_buffer; |
|||
|
|||
p_sout_buffer = |
|||
sout_BufferNew( p_pack->p_sout_input->p_sout, i_size ); |
|||
if( !p_sout_buffer ) |
|||
{ |
|||
p_pack->p_fifo->b_error = 1; |
|||
return; |
|||
} |
|||
/* TODO: memcpy of the pes packet */ |
|||
for( i_buffer = 0, p_data = p_pes->p_first; |
|||
p_data != NULL && i_buffer < i_size; |
|||
p_data = p_data->p_next) |
|||
{ |
|||
size_t i_copy; |
|||
|
|||
i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start, |
|||
i_size - i_buffer ); |
|||
if( i_copy > 0 ) |
|||
{ |
|||
p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer, |
|||
p_data->p_payload_start, |
|||
i_copy ); |
|||
} |
|||
i_buffer += i_copy; |
|||
} |
|||
|
|||
sout_InputSendBuffer( p_pack->p_sout_input, |
|||
p_sout_buffer ); |
|||
} |
|||
|
|||
input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes ); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* EndThread : packetizer thread destruction |
|||
*****************************************************************************/ |
|||
static void EndThread ( packetizer_thread_t *p_pack) |
|||
{ |
|||
if( p_pack->p_sout_input ) |
|||
{ |
|||
sout_InputDelete( p_pack->p_sout_input ); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,358 @@ |
|||
/*****************************************************************************
|
|||
* mpeg4video.c: |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: mpeg4video.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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/aout.h> |
|||
#include <vlc/decoder.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
|
|||
#include <stdlib.h> /* malloc(), free() */ |
|||
#include <string.h> /* strdup() */ |
|||
|
|||
/*****************************************************************************
|
|||
* Local prototypes |
|||
*****************************************************************************/ |
|||
typedef struct packetizer_thread_s |
|||
{ |
|||
/* Input properties */ |
|||
decoder_fifo_t *p_fifo; |
|||
bit_stream_t bit_stream; |
|||
|
|||
mtime_t i_dts; |
|||
|
|||
/* Output properties */ |
|||
sout_input_t *p_sout_input; |
|||
sout_packet_format_t output_format; |
|||
|
|||
|
|||
sout_buffer_t *p_vol; |
|||
int i_vop_since_vol; |
|||
} packetizer_thread_t; |
|||
|
|||
static int Open ( vlc_object_t * ); |
|||
static int Run ( decoder_fifo_t * ); |
|||
|
|||
static int InitThread ( packetizer_thread_t * ); |
|||
static void PacketizeThread ( packetizer_thread_t * ); |
|||
static void EndThread ( packetizer_thread_t * ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
|
|||
vlc_module_begin(); |
|||
set_description( _("MPEG-4 packetizer") ); |
|||
set_capability( "packetizer", 50 ); |
|||
set_callbacks( Open, NULL ); |
|||
vlc_module_end(); |
|||
|
|||
#define VIDEO_OBJECT_MASK 0x01f |
|||
#define VIDEO_OBJECT_LAYER_MASK 0x00f |
|||
|
|||
#define VIDEO_OBJECT_START_CODE 0x100 |
|||
#define VIDEO_OBJECT_LAYER_START_CODE 0x120 |
|||
#define VISUAL_OBJECT_SEQUENCE_START_CODE 0x1b0 |
|||
#define VISUAL_OBJECT_SEQUENCE_END_CODE 0x1b1 |
|||
#define USER_DATA_START_CODE 0x1b2 |
|||
#define GROUP_OF_VOP_START_CODE 0x1b3 |
|||
#define VIDEO_SESSION_ERROR_CODE 0x1b4 |
|||
#define VISUAL_OBJECT_START_CODE 0x1b5 |
|||
#define VOP_START_CODE 0x1b6 |
|||
#define FACE_OBJECT_START_CODE 0x1ba |
|||
#define FACE_OBJECT_PLANE_START_CODE 0x1bb |
|||
#define MESH_OBJECT_START_CODE 0x1bc |
|||
#define MESH_OBJECT_PLANE_START_CODE 0x1bd |
|||
#define STILL_TEXTURE_OBJECT_START_CODE 0x1be |
|||
#define TEXTURE_SPATIAL_LAYER_START_CODE 0x1bf |
|||
#define TEXTURE_SNR_LAYER_START_CODE 0x1c0 |
|||
|
|||
/*****************************************************************************
|
|||
* OpenDecoder: probe the packetizer and return score |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to choose. |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; |
|||
|
|||
p_fifo->pf_run = Run; |
|||
|
|||
switch( p_fifo->i_fourcc ) |
|||
{ |
|||
case VLC_FOURCC( 'm', 'p', '4', 'v'): |
|||
case VLC_FOURCC( 'D', 'I', 'V', 'X'): |
|||
case VLC_FOURCC( 'd', 'i', 'v', 'x'): |
|||
case VLC_FOURCC( 'X', 'V', 'I', 'D'): |
|||
case VLC_FOURCC( 'X', 'v', 'i', 'D'): |
|||
case VLC_FOURCC( 'x', 'v', 'i', 'd'): |
|||
case VLC_FOURCC( 'D', 'X', '5', '0'): |
|||
return VLC_SUCCESS; |
|||
default: |
|||
return VLC_EGENERIC; |
|||
} |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* RunDecoder: this function is called just after the thread is created |
|||
*****************************************************************************/ |
|||
static int Run( decoder_fifo_t *p_fifo ) |
|||
{ |
|||
packetizer_thread_t *p_pack; |
|||
int b_error; |
|||
|
|||
msg_Info( p_fifo, "Running MPEG-4 packetizer" ); |
|||
if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) ) |
|||
{ |
|||
msg_Err( p_fifo, "out of memory" ); |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
memset( p_pack, 0, sizeof( packetizer_thread_t ) ); |
|||
|
|||
p_pack->p_fifo = p_fifo; |
|||
|
|||
if( InitThread( p_pack ) != 0 ) |
|||
{ |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
PacketizeThread( p_pack ); |
|||
} |
|||
|
|||
|
|||
if( ( b_error = p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
DecoderError( p_pack->p_fifo ); |
|||
} |
|||
|
|||
EndThread( p_pack ); |
|||
if( b_error ) |
|||
{ |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
#define FREE( p ) if( p ) free( p ); p = NULL |
|||
|
|||
static int CopyUntilNextStartCode( packetizer_thread_t *p_pack, |
|||
sout_buffer_t *p_sout_buffer, |
|||
int *pi_pos ) |
|||
{ |
|||
int i_copy = 0; |
|||
|
|||
do |
|||
{ |
|||
p_sout_buffer->p_buffer[(*pi_pos)++] = |
|||
GetBits( &p_pack->bit_stream, 8 ); |
|||
i_copy++; |
|||
|
|||
if( *pi_pos + 2048 > p_sout_buffer->i_allocated_size ) |
|||
{ |
|||
sout_BufferRealloc( p_pack->p_sout_input->p_sout, |
|||
p_sout_buffer, |
|||
p_sout_buffer->i_allocated_size + 50 * 1024); |
|||
} |
|||
|
|||
} while( ShowBits( &p_pack->bit_stream, 24 ) != 0x01 && |
|||
!p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error ); |
|||
|
|||
return( i_copy ); |
|||
} |
|||
|
|||
static int sout_BufferAddMem( sout_instance_t *p_sout, |
|||
sout_buffer_t *p_buffer, |
|||
int i_mem, |
|||
uint8_t *p_mem ) |
|||
{ |
|||
if( p_buffer->i_size + i_mem >= p_buffer->i_allocated_size ) |
|||
{ |
|||
sout_BufferRealloc( p_sout, |
|||
p_buffer, |
|||
p_buffer->i_size + i_mem + 1024 ); |
|||
} |
|||
memcpy( p_buffer->p_buffer + p_buffer->i_size, p_mem, i_mem ); |
|||
p_buffer->i_size += i_mem; |
|||
|
|||
return( i_mem ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* InitThread: initialize data before entering main loop |
|||
*****************************************************************************/ |
|||
|
|||
static int InitThread( packetizer_thread_t *p_pack ) |
|||
{ |
|||
p_pack->i_dts = 0; |
|||
p_pack->p_vol = NULL; |
|||
p_pack->i_vop_since_vol = 0; |
|||
p_pack->output_format.i_cat = VIDEO_ES; |
|||
p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' ); |
|||
|
|||
if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo, |
|||
NULL, NULL ) != VLC_SUCCESS ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, "cannot initialize bitstream" ); |
|||
return -1; |
|||
} |
|||
|
|||
p_pack->p_sout_input = |
|||
sout_InputNew( p_pack->p_fifo, |
|||
&p_pack->output_format ); |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, |
|||
"cannot add a new stream" ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* PacketizeThread: packetize an unit (here copy a complete pes) |
|||
*****************************************************************************/ |
|||
static void PacketizeThread( packetizer_thread_t *p_pack ) |
|||
{ |
|||
sout_instance_t *p_sout = p_pack->p_sout_input->p_sout; |
|||
sout_buffer_t *p_frame; |
|||
|
|||
uint32_t i_startcode; |
|||
|
|||
/* Idea: Copy until a vop has been found
|
|||
* Once a videoobject & videoobjectlayer has been found we save it |
|||
*/ |
|||
|
|||
p_frame = sout_BufferNew( p_sout, 20*1024 ); // FIXME
|
|||
p_frame->i_size = 0; |
|||
|
|||
for( ;; ) |
|||
{ |
|||
while( ( ( i_startcode = ShowBits( &p_pack->bit_stream, 32 ) )&0xffffff00 ) != 0x00000100 ) |
|||
{ |
|||
RemoveBits( &p_pack->bit_stream, 8 ); |
|||
} |
|||
|
|||
if( i_startcode == VISUAL_OBJECT_SEQUENCE_START_CODE ) |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "<visuel_object_sequence>" ); |
|||
RemoveBits32( &p_pack->bit_stream ); |
|||
} |
|||
else if( i_startcode == VISUAL_OBJECT_SEQUENCE_END_CODE ) |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "</visuel_object_sequence>" ); |
|||
RemoveBits32( &p_pack->bit_stream ); |
|||
} |
|||
else |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "start code:0x%8.8x", i_startcode ); |
|||
|
|||
if( ( i_startcode & ~VIDEO_OBJECT_MASK ) == VIDEO_OBJECT_START_CODE ) |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "<video_object>" ); |
|||
CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size ); |
|||
} |
|||
else if( ( i_startcode & ~VIDEO_OBJECT_LAYER_MASK ) == VIDEO_OBJECT_LAYER_START_CODE ) |
|||
{ |
|||
/* first: save it */ |
|||
if( p_pack->p_vol == NULL ) |
|||
{ |
|||
p_pack->p_vol = sout_BufferNew( p_sout, 1024 ); |
|||
} |
|||
p_pack->p_vol->i_size = 0; |
|||
CopyUntilNextStartCode( p_pack, p_pack->p_vol, &p_pack->p_vol->i_size ); |
|||
p_pack->i_vop_since_vol = 0; |
|||
|
|||
/* then: add it to p_frame */ |
|||
sout_BufferAddMem( p_sout, p_frame, |
|||
p_pack->p_vol->i_size, |
|||
p_pack->p_vol->p_buffer ); |
|||
} |
|||
else if( i_startcode == GROUP_OF_VOP_START_CODE ) |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "<group_of_vop>" ); |
|||
if( p_pack->p_vol && p_pack->i_vop_since_vol > 100 ) // FIXME
|
|||
{ |
|||
sout_BufferAddMem( p_sout, p_frame, |
|||
p_pack->p_vol->i_size, |
|||
p_pack->p_vol->p_buffer ); |
|||
p_pack->i_vop_since_vol = 0; |
|||
} |
|||
CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size ); |
|||
} |
|||
else if( i_startcode == VOP_START_CODE ) |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "<vop>" ); |
|||
if( p_pack->p_vol && p_pack->i_vop_since_vol > 100 ) // FIXME
|
|||
{ |
|||
sout_BufferAddMem( p_sout, p_frame, |
|||
p_pack->p_vol->i_size, |
|||
p_pack->p_vol->p_buffer ); |
|||
p_pack->i_vop_since_vol = 0; |
|||
} |
|||
CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size ); |
|||
p_pack->i_vop_since_vol++; |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
msg_Dbg( p_pack->p_fifo, "unknown start code" ); |
|||
CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size ); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
p_frame->i_length = 1000000 / 25; |
|||
p_frame->i_bitrate= 0; |
|||
p_frame->i_dts = p_pack->i_dts; |
|||
p_frame->i_pts = p_pack->i_dts; |
|||
|
|||
p_pack->i_dts += 1000000 / 25; |
|||
sout_InputSendBuffer( p_pack->p_sout_input, p_frame ); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* EndThread : packetizer thread destruction |
|||
*****************************************************************************/ |
|||
static void EndThread ( packetizer_thread_t *p_pack) |
|||
{ |
|||
if( p_pack->p_sout_input ) |
|||
{ |
|||
sout_InputDelete( p_pack->p_sout_input ); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,370 @@ |
|||
/*****************************************************************************
|
|||
* mpegaudio.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: mpegaudio.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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/aout.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" /* WAVEFORMATEX BITMAPINFOHEADER */ |
|||
/*****************************************************************************
|
|||
* Local prototypes |
|||
*****************************************************************************/ |
|||
typedef struct packetizer_s |
|||
{ |
|||
/* Input properties */ |
|||
decoder_fifo_t *p_fifo; |
|||
bit_stream_t bit_stream; |
|||
|
|||
/* Output properties */ |
|||
sout_input_t *p_sout_input; |
|||
sout_packet_format_t output_format; |
|||
|
|||
uint64_t i_samplescount; |
|||
uint32_t i_samplespersecond; |
|||
|
|||
} packetizer_t; |
|||
|
|||
static int Open ( vlc_object_t * ); |
|||
static int Run ( decoder_fifo_t * ); |
|||
|
|||
static int InitThread ( packetizer_t * ); |
|||
static void PacketizeThread ( packetizer_t * ); |
|||
static void EndThread ( packetizer_t * ); |
|||
|
|||
#define FREE( p ) if( p ) free( p ); p = NULL |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
|
|||
vlc_module_begin(); |
|||
set_description( _("MPEG-I/II audio packetizer") ); |
|||
set_capability( "packetizer", 50 ); |
|||
set_callbacks( Open, NULL ); |
|||
vlc_module_end(); |
|||
|
|||
|
|||
static int mpegaudio_bitrate[2][3][16] = |
|||
{ |
|||
{ |
|||
/* v1 l1 */ |
|||
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, |
|||
/* v1 l2 */ |
|||
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, |
|||
/* v1 l3 */ |
|||
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} |
|||
}, |
|||
|
|||
{ |
|||
/* v2 l1 */ |
|||
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0}, |
|||
/* v2 l2 */ |
|||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, |
|||
/* v2 l3 */ |
|||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0} |
|||
} |
|||
|
|||
}; |
|||
|
|||
static int mpegaudio_samplerate[2][4] = /* version 1 then 2 */ |
|||
{ |
|||
{ 44100, 48000, 32000, 0 }, |
|||
{ 22050, 24000, 16000, 0 } |
|||
}; |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* OpenDecoder: probe the packetizer and return score |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to choose. |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; |
|||
|
|||
if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'a') ) |
|||
{ |
|||
return VLC_EGENERIC; |
|||
} |
|||
|
|||
p_fifo->pf_run = Run; |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* RunDecoder: this function is called just after the thread is created |
|||
*****************************************************************************/ |
|||
static int Run( decoder_fifo_t *p_fifo ) |
|||
{ |
|||
packetizer_t *p_pack; |
|||
int b_error; |
|||
|
|||
msg_Info( p_fifo, "Running mpegaudio packetizer" ); |
|||
if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) ) |
|||
{ |
|||
msg_Err( p_fifo, "out of memory" ); |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
memset( p_pack, 0, sizeof( packetizer_t ) ); |
|||
|
|||
p_pack->p_fifo = p_fifo; |
|||
|
|||
if( InitThread( p_pack ) != 0 ) |
|||
{ |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
PacketizeThread( p_pack ); |
|||
} |
|||
|
|||
|
|||
if( ( b_error = p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
DecoderError( p_pack->p_fifo ); |
|||
} |
|||
|
|||
EndThread( p_pack ); |
|||
|
|||
FREE( p_pack ); |
|||
|
|||
if( b_error ) |
|||
{ |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* InitThread: initialize data before entering main loop |
|||
*****************************************************************************/ |
|||
|
|||
static int InitThread( packetizer_t *p_pack ) |
|||
{ |
|||
|
|||
p_pack->output_format.i_cat = AUDIO_ES; |
|||
p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc; |
|||
|
|||
p_pack->output_format.p_format = NULL; |
|||
|
|||
p_pack->p_sout_input = NULL; |
|||
|
|||
p_pack->i_samplescount = 0; |
|||
p_pack->i_samplespersecond = 0; |
|||
|
|||
if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo, |
|||
NULL, NULL ) != VLC_SUCCESS ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, "cannot initialize bitstream" ); |
|||
return -1; |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* PacketizeThread: packetize an unit (here copy a complete pes) |
|||
*****************************************************************************/ |
|||
static void PacketizeThread( packetizer_t *p_pack ) |
|||
{ |
|||
sout_buffer_t *p_sout_buffer; |
|||
size_t i_size; |
|||
|
|||
uint32_t i_sync, i_header; |
|||
int i_version, i_layer; |
|||
int i_channels, i_samplerate, i_bitrate; |
|||
int i_samplesperframe, i_framelength; |
|||
int i_skip = 0; |
|||
/* search a valid start code */ |
|||
for( ;; ) |
|||
{ |
|||
int i_crc, i_bitrate_index, i_samplerate_index; |
|||
int i_padding, i_extention, i_mode, i_modeext, i_copyright; |
|||
int i_original, i_emphasis; |
|||
|
|||
RealignBits( &p_pack->bit_stream ); |
|||
|
|||
|
|||
while( ShowBits( &p_pack->bit_stream, 12 ) != 0x0fff && |
|||
!p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error ) |
|||
{ |
|||
//msg_Warn( p_pack->p_fifo, "trash..." );
|
|||
RemoveBits( &p_pack->bit_stream, 8 ); |
|||
i_skip++; |
|||
} |
|||
|
|||
if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error ) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
i_sync = GetBits( &p_pack->bit_stream, 12 ); |
|||
i_header = ShowBits( &p_pack->bit_stream, 20 ); |
|||
|
|||
i_version = 1 - GetBits( &p_pack->bit_stream, 1 ); |
|||
i_layer = 3 - GetBits( &p_pack->bit_stream, 2 ); |
|||
i_crc = 1 - GetBits( &p_pack->bit_stream, 1 ); |
|||
i_bitrate_index = GetBits( &p_pack->bit_stream, 4 ); |
|||
i_samplerate_index = GetBits( &p_pack->bit_stream, 2 ); |
|||
i_padding = GetBits( &p_pack->bit_stream, 1 ); |
|||
i_extention = GetBits( &p_pack->bit_stream, 1 ); |
|||
i_mode = GetBits( &p_pack->bit_stream, 2 ); |
|||
i_modeext = GetBits( &p_pack->bit_stream, 2 ); |
|||
i_copyright = GetBits( &p_pack->bit_stream, 1 ); |
|||
i_original = GetBits( &p_pack->bit_stream, 1 ); |
|||
i_emphasis = GetBits( &p_pack->bit_stream, 2 ); |
|||
|
|||
if( i_layer != 3 && |
|||
i_bitrate_index > 0x00 && i_bitrate_index < 0x0f && |
|||
i_samplerate_index != 0x03 && |
|||
i_emphasis != 0x02 ) |
|||
{ |
|||
i_channels = ( i_mode == 3 ) ? 1 : 2; |
|||
i_bitrate = mpegaudio_bitrate[i_version][i_layer][i_bitrate_index]; |
|||
i_samplerate = mpegaudio_samplerate[i_version][i_samplerate_index]; |
|||
switch( i_layer ) |
|||
{ |
|||
case 0: |
|||
i_framelength = ( ( i_version ? 6000 : 12000 ) * |
|||
i_bitrate / i_samplerate + i_padding ) * 4; |
|||
break; |
|||
case 1: |
|||
case 2: |
|||
i_framelength = ( i_version ? 72000 : 144000 ) * |
|||
i_bitrate / i_samplerate + i_padding; |
|||
break; |
|||
default: |
|||
i_framelength = 0; |
|||
} |
|||
switch( i_layer ) |
|||
{ |
|||
case 0: |
|||
i_samplesperframe = 384; |
|||
break; |
|||
case 1: |
|||
i_samplesperframe = 1152; |
|||
break; |
|||
case 2: |
|||
i_samplesperframe = i_version ? 1152 : 576; |
|||
break; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
/* add a input for the stream ouput */ |
|||
WAVEFORMATEX *p_wf; |
|||
|
|||
p_wf = malloc( sizeof( WAVEFORMATEX ) ); |
|||
p_pack->output_format.p_format = (void*)p_wf; |
|||
|
|||
p_wf->wFormatTag = WAVE_FORMAT_MPEG; |
|||
p_wf->nChannels = i_channels; |
|||
p_wf->nSamplesPerSec = i_samplerate; |
|||
p_wf->nAvgBytesPerSec = 0; |
|||
p_wf->nBlockAlign = 1; |
|||
p_wf->wBitsPerSample = 0; |
|||
p_wf->cbSize = 0; // FIXME there are more field for mpegaudio
|
|||
|
|||
p_pack->p_sout_input = |
|||
sout_InputNew( p_pack->p_fifo, |
|||
&p_pack->output_format ); |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, |
|||
"cannot add a new stream" ); |
|||
p_pack->p_fifo->b_error = 1; |
|||
return; |
|||
} |
|||
msg_Dbg( p_pack->p_fifo, |
|||
"v:%d l:%d channels:%d samplerate:%d bitrate:%d size:%d", |
|||
i_version, i_layer, i_channels, i_samplerate, |
|||
i_bitrate, i_framelength ); |
|||
} |
|||
|
|||
i_size = __MAX( i_framelength, 4 ); |
|||
// msg_Dbg( p_pack->p_fifo, "frame length %d b", i_size );
|
|||
p_sout_buffer = |
|||
sout_BufferNew( p_pack->p_sout_input->p_sout, i_size ); |
|||
if( !p_sout_buffer ) |
|||
{ |
|||
p_pack->p_fifo->b_error = 1; |
|||
return; |
|||
} |
|||
p_sout_buffer->p_buffer[0] = ( i_sync >> 4 )&0xff; |
|||
p_sout_buffer->p_buffer[1] = |
|||
( ( i_sync << 4 )&0xf0 ) | ( ( i_header >> 16 )&0x0f ); |
|||
p_sout_buffer->p_buffer[2] = ( i_header >> 8 )&0xff; |
|||
p_sout_buffer->p_buffer[3] = ( i_header )&0xff; |
|||
p_sout_buffer->i_bitrate = i_bitrate; |
|||
|
|||
p_sout_buffer->i_pts = |
|||
p_sout_buffer->i_dts = |
|||
(uint64_t)1000000 * |
|||
(uint64_t)p_pack->i_samplescount / |
|||
(uint64_t)i_samplerate; |
|||
p_sout_buffer->i_length = |
|||
(uint64_t)1000000 * |
|||
(uint64_t)i_samplesperframe / |
|||
(uint64_t)i_samplerate; |
|||
|
|||
p_pack->i_samplescount += i_samplesperframe; |
|||
|
|||
/* we are already aligned */ |
|||
GetChunk( &p_pack->bit_stream, |
|||
p_sout_buffer->p_buffer + 4, |
|||
i_size - 4 ); |
|||
|
|||
sout_InputSendBuffer( p_pack->p_sout_input, |
|||
p_sout_buffer ); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* EndThread : packetizer thread destruction |
|||
*****************************************************************************/ |
|||
static void EndThread ( packetizer_t *p_pack) |
|||
{ |
|||
if( p_pack->p_sout_input ) |
|||
{ |
|||
sout_InputDelete( p_pack->p_sout_input ); |
|||
} |
|||
} |
|||
@ -0,0 +1,395 @@ |
|||
/*****************************************************************************
|
|||
* mpegvideo.c |
|||
***************************************************************************** |
|||
* Copyright (C) 2001, 2002 VideoLAN |
|||
* $Id: mpegvideo.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $ |
|||
* |
|||
* Authors: Laurent Aimar <fenrir@via.ecp.fr> |
|||
* Eric Petit <titer@videolan.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/decoder.h> |
|||
#include <vlc/input.h> |
|||
#include <vlc/sout.h> |
|||
#include "codecs.h" /* WAVEFORMATEX BITMAPINFOHEADER */ |
|||
|
|||
#include <stdlib.h> /* malloc(), free() */ |
|||
#include <string.h> /* strdup() */ |
|||
|
|||
/*****************************************************************************
|
|||
* Local prototypes |
|||
*****************************************************************************/ |
|||
typedef struct packetizer_s |
|||
{ |
|||
/* Input properties */ |
|||
decoder_fifo_t *p_fifo; |
|||
bit_stream_t bit_stream; |
|||
|
|||
/* Output properties */ |
|||
sout_input_t *p_sout_input; |
|||
sout_packet_format_t output_format; |
|||
|
|||
mtime_t i_last_dts; |
|||
mtime_t i_last_ref_pts; |
|||
double d_frame_rate; |
|||
uint8_t p_sequence_header[150]; |
|||
int i_sequence_header_length; |
|||
int i_last_sequence_header; |
|||
|
|||
} packetizer_t; |
|||
|
|||
static int Open ( vlc_object_t * ); |
|||
static int Run ( decoder_fifo_t * ); |
|||
|
|||
static int InitThread ( packetizer_t * ); |
|||
static void PacketizeThread ( packetizer_t * ); |
|||
static void EndThread ( packetizer_t * ); |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor |
|||
*****************************************************************************/ |
|||
|
|||
vlc_module_begin(); |
|||
set_description( _("MPEG-I/II video packetizer") ); |
|||
set_capability( "packetizer", 50 ); |
|||
set_callbacks( Open, NULL ); |
|||
vlc_module_end(); |
|||
|
|||
/*****************************************************************************
|
|||
* OpenDecoder: probe the packetizer and return score |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to choose. |
|||
*****************************************************************************/ |
|||
static int Open( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; |
|||
|
|||
if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'v') ) |
|||
{ |
|||
return VLC_EGENERIC; |
|||
} |
|||
|
|||
p_fifo->pf_run = Run; |
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* RunDecoder: this function is called just after the thread is created |
|||
*****************************************************************************/ |
|||
static int Run( decoder_fifo_t *p_fifo ) |
|||
{ |
|||
packetizer_t *p_pack; |
|||
int b_error; |
|||
|
|||
msg_Info( p_fifo, "Running mpegvideo packetizer" ); |
|||
if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) ) |
|||
{ |
|||
msg_Err( p_fifo, "out of memory" ); |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
memset( p_pack, 0, sizeof( packetizer_t ) ); |
|||
|
|||
p_pack->p_fifo = p_fifo; |
|||
|
|||
if( InitThread( p_pack ) != 0 ) |
|||
{ |
|||
DecoderError( p_fifo ); |
|||
return( -1 ); |
|||
} |
|||
|
|||
while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
PacketizeThread( p_pack ); |
|||
} |
|||
|
|||
|
|||
if( ( b_error = p_pack->p_fifo->b_error ) ) |
|||
{ |
|||
DecoderError( p_pack->p_fifo ); |
|||
} |
|||
|
|||
EndThread( p_pack ); |
|||
|
|||
if( p_pack ) |
|||
{ |
|||
free( p_pack ); |
|||
} |
|||
|
|||
if( b_error ) |
|||
{ |
|||
return( -1 ); |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* InitThread: initialize data before entering main loop |
|||
*****************************************************************************/ |
|||
|
|||
static int InitThread( packetizer_t *p_pack ) |
|||
{ |
|||
|
|||
p_pack->output_format.i_cat = VIDEO_ES; |
|||
p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc; |
|||
|
|||
p_pack->p_sout_input = NULL; |
|||
|
|||
if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo, |
|||
NULL, NULL ) != VLC_SUCCESS ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, "cannot initialize bitstream" ); |
|||
return -1; |
|||
} |
|||
|
|||
return( 0 ); |
|||
} |
|||
|
|||
/* from ISO 13818-2 */ |
|||
/* converting frame_rate_code to frame_rate */ |
|||
static const double pd_frame_rates[16] = |
|||
{ |
|||
0, 24000/1001, 24, 25, 30000/1001, 30, 50, 60000/1001, 60, |
|||
0, 0, 0, 0, 0, 0, 0 |
|||
}; |
|||
|
|||
static int CopyUntilNextStartCode( packetizer_t *p_pack, |
|||
sout_buffer_t *p_sout_buffer, |
|||
int *pi_pos ) |
|||
{ |
|||
int i_copy = 0; |
|||
|
|||
do |
|||
{ |
|||
p_sout_buffer->p_buffer[(*pi_pos)++] = |
|||
GetBits( &p_pack->bit_stream, 8 ); |
|||
i_copy++; |
|||
|
|||
if( *pi_pos + 2048 > p_sout_buffer->i_allocated_size ) |
|||
{ |
|||
sout_BufferRealloc( p_pack->p_sout_input->p_sout, |
|||
p_sout_buffer, |
|||
p_sout_buffer->i_allocated_size + 50 * 1024); |
|||
} |
|||
|
|||
} while( ShowBits( &p_pack->bit_stream, 24 ) != 0x01 && |
|||
!p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error ); |
|||
|
|||
return( i_copy ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* PacketizeThread: packetize an unit (here copy a complete pes) |
|||
*****************************************************************************/ |
|||
static void PacketizeThread( packetizer_t *p_pack ) |
|||
{ |
|||
sout_buffer_t *p_sout_buffer = NULL; |
|||
int32_t i_pos; |
|||
int i_temporal_ref = 0; |
|||
int i_skipped; |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
byte_t p_temp[512];/* 150 bytes is the maximal size
|
|||
of a sequence_header + sequence_extension */ |
|||
int i_frame_rate_code; |
|||
BITMAPINFOHEADER *p_bih; |
|||
|
|||
p_bih = malloc( sizeof( BITMAPINFOHEADER ) ); |
|||
p_pack->output_format.p_format = (void*)p_bih; |
|||
|
|||
/* skip data until we find a sequence_header_code */ |
|||
/* TODO: store skipped somewhere so can send it to the mux
|
|||
* after the input is created */ |
|||
i_skipped = 0; |
|||
while( ShowBits( &p_pack->bit_stream, 32 ) != 0x1B3 ) |
|||
{ |
|||
RemoveBits( &p_pack->bit_stream, 8 ); |
|||
i_skipped++; |
|||
} |
|||
msg_Warn( p_pack->p_fifo, "sequence_header_code found (%d skipped)", |
|||
i_skipped ); |
|||
|
|||
/* copy the start_code */ |
|||
i_pos = 0; |
|||
GetChunk( &p_pack->bit_stream, p_temp, 4 ); i_pos += 4; |
|||
|
|||
p_bih->biSize = sizeof( BITMAPINFOHEADER ); |
|||
/* horizontal_size_value */ |
|||
p_bih->biWidth = ShowBits( &p_pack->bit_stream, 12 ); |
|||
/* vertical_size_value */ |
|||
p_bih->biHeight = ShowBits( &p_pack->bit_stream, 24 ) & 0xFFF; |
|||
/* frame_rate_code */ |
|||
i_frame_rate_code = ShowBits( &p_pack->bit_stream, 32 ) & 0xF; |
|||
p_bih->biPlanes = 1; |
|||
p_bih->biBitCount = 0; |
|||
p_bih->biCompression = 0x6D706732; /* mpg2 */ |
|||
p_bih->biSizeImage = 0; |
|||
p_bih->biXPelsPerMeter = 0; |
|||
p_bih->biYPelsPerMeter = 0; |
|||
p_bih->biClrUsed = 0; |
|||
p_bih->biClrImportant = 0; |
|||
|
|||
/* copy headers */ |
|||
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 7 ); i_pos += 7; |
|||
|
|||
/* intra_quantiser_matrix [non_intra_quantiser_matrix] */ |
|||
if( ShowBits( &p_pack->bit_stream, 7 ) & 0x1 ) |
|||
{ |
|||
|
|||
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 64 ); i_pos += 64; |
|||
|
|||
if( ShowBits( &p_pack->bit_stream, 8 ) & 0x1 ) |
|||
{ |
|||
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 65); i_pos += 65; |
|||
} |
|||
} |
|||
/* non_intra_quantiser_matrix */ |
|||
else if( ShowBits( &p_pack->bit_stream, 8 ) & 0x1 ) |
|||
{ |
|||
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 65); i_pos += 65; |
|||
} |
|||
/* nothing */ |
|||
else |
|||
{ |
|||
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 1 ); i_pos += 1; |
|||
} |
|||
|
|||
/* sequence_extension (10 bytes) */ |
|||
if( ShowBits( &p_pack->bit_stream, 32 ) != 0x1B5 ) |
|||
msg_Dbg( p_pack->p_fifo, "ARRGG no extension_start_code" ); |
|||
else |
|||
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 10 ); i_pos += 10; |
|||
|
|||
/* remember sequence_header and sequence_extention */ |
|||
memcpy( p_pack->p_sequence_header, p_temp, i_pos ); |
|||
p_pack->i_sequence_header_length = i_pos; |
|||
|
|||
p_pack->d_frame_rate = pd_frame_rates[i_frame_rate_code]; |
|||
|
|||
msg_Warn( p_pack->p_fifo, |
|||
"creating input (image size %dx%d, frame rate %.2f)", |
|||
p_bih->biWidth, p_bih->biHeight, p_pack->d_frame_rate ); |
|||
|
|||
/* now we have informations to create the input */ |
|||
p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo, |
|||
&p_pack->output_format ); |
|||
|
|||
if( !p_pack->p_sout_input ) |
|||
{ |
|||
msg_Err( p_pack->p_fifo, "cannot add a new stream" ); |
|||
return; |
|||
} |
|||
|
|||
p_sout_buffer = sout_BufferNew( p_pack->p_sout_input->p_sout, |
|||
100 * 1024 ); |
|||
p_sout_buffer->i_size = i_pos; |
|||
memcpy( p_sout_buffer->p_buffer, p_temp, i_pos ); |
|||
|
|||
} |
|||
else |
|||
{ |
|||
p_sout_buffer = |
|||
sout_BufferNew( p_pack->p_sout_input->p_sout, 100 * 1024 ); |
|||
i_pos = 0; |
|||
} |
|||
|
|||
p_pack->i_last_sequence_header++; |
|||
|
|||
for( ;; ) |
|||
{ |
|||
uint32_t i_code; |
|||
if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error ) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
i_code = ShowBits( &p_pack->bit_stream, 32 ); |
|||
|
|||
if( i_code == 0x1B8 ) /* GOP */ |
|||
{ |
|||
/* usefull for bad MPEG-1 : repeat the sequence_header
|
|||
every second */ |
|||
if( p_pack->i_last_sequence_header > (int) p_pack->d_frame_rate ) |
|||
{ |
|||
memcpy( p_sout_buffer->p_buffer + i_pos, |
|||
p_pack->p_sequence_header, |
|||
p_pack->i_sequence_header_length ); |
|||
i_pos += p_pack->i_sequence_header_length; |
|||
p_pack->i_last_sequence_header = 0; |
|||
} |
|||
|
|||
p_pack->i_last_ref_pts = |
|||
p_pack->i_last_dts + 40000; /* FIXME */ |
|||
CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos ); |
|||
} |
|||
else if( i_code == 0x100 ) /* Picture */ |
|||
{ |
|||
/* picture_start_code */ |
|||
GetChunk( &p_pack->bit_stream, |
|||
p_sout_buffer->p_buffer + i_pos, 4 ); i_pos += 4; |
|||
i_temporal_ref = ShowBits( &p_pack->bit_stream, 10 ); |
|||
|
|||
CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos ); |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
if( i_code == 0x1B3 ) |
|||
{ |
|||
p_pack->i_last_sequence_header = 0; |
|||
} |
|||
CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos ); |
|||
} |
|||
} |
|||
|
|||
sout_BufferRealloc( p_pack->p_sout_input->p_sout, |
|||
p_sout_buffer, i_pos ); |
|||
p_sout_buffer->i_size = i_pos; |
|||
|
|||
p_sout_buffer->i_dts = p_pack->i_last_dts; |
|||
p_sout_buffer->i_pts = p_pack->i_last_ref_pts + |
|||
i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate ); |
|||
|
|||
p_sout_buffer->i_length = (uint64_t)1000000 / p_pack->d_frame_rate; |
|||
p_sout_buffer->i_bitrate = (int)( 8 * i_pos * p_pack->d_frame_rate ); |
|||
|
|||
// msg_Dbg( p_pack->p_fifo, "frame length %d b", i_pos );
|
|||
|
|||
sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer ); |
|||
|
|||
p_pack->i_last_dts += (mtime_t)( 1000000 / p_pack->d_frame_rate ); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* EndThread : packetizer thread destruction |
|||
*****************************************************************************/ |
|||
static void EndThread ( packetizer_t *p_pack) |
|||
{ |
|||
if( p_pack->p_sout_input ) |
|||
{ |
|||
sout_InputDelete( p_pack->p_sout_input ); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue