📄 nuv.c
字号:
/***************************************************************************** * nuv.c: ***************************************************************************** * Copyright (C) 2005 VideoLAN * $Id: $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <vlc/vlc.h>#include <vlc/input.h>/* TODO: * - complete support (add support for rtjpeg and raw) * - better seek support (to key frame) * - control GET_LENGTH (harder, unless we have an extended header+index) * - test *//***************************************************************************** * Module descriptor *****************************************************************************/static int Open ( vlc_object_t * );static void Close ( vlc_object_t * );vlc_module_begin(); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_DEMUX ); set_description( _("Nuv demuxer") ); set_capability( "demux2", 145 ); set_callbacks( Open, Close ); add_shortcut( "nuv" );vlc_module_end();/***************************************************************************** * Local prototypes *****************************************************************************/static int Demux ( demux_t * );static int Control( demux_t *, int, va_list );/* */typedef struct{ int64_t i_time; int64_t i_offset;} demux_index_entry_t;typedef struct{ int i_idx; int i_idx_max; demux_index_entry_t *idx;} demux_index_t;static void demux_IndexInit( demux_index_t * );static void demux_IndexClean( demux_index_t * );static void demux_IndexAppend( demux_index_t *, int64_t i_time, int64_t i_offset );/* Convert a time into offset */static int64_t demux_IndexConvertTime( demux_index_t *, int64_t i_time );/* Find the nearest offset in the index */static int64_t demux_IndexFindOffset( demux_index_t *, int64_t i_offset );/* */typedef struct{ char id[12]; /* "NuppelVideo\0" or "MythTVVideo\0" */ char version[5]; /* "x.xx\0" */ int i_width; int i_height; int i_width_desired; int i_height_desired; char i_mode; /* P progressive, I interlaced */ double d_aspect; /* 1.0 squared pixel */ double d_fps; int i_video_blocks; /* 0 no video, -1 unknown */ int i_audio_blocks; int i_text_blocks; int i_keyframe_distance;} header_t;typedef struct{ char i_type; /* A: audio, V: video, S: sync; T: test R: Seekpoint (string:RTjjjjjjjj) D: Extra data for codec */ char i_compression; /* V: 0 uncompressed 1 RTJpeg 2 RTJpeg+lzo N black frame L copy last A: 0 uncompressed (44100 1-bits, 2ch) 1 lzo 2 layer 2 3 layer 3 F flac S shorten N null frame loudless L copy last S: B audio and vdeo sync point A audio sync info (timecode == effective dsp frequency*100) V next video sync (timecode == next video frame num) S audio,video,text correlation */ char i_keyframe; /* 0 keyframe, else no no key frame */ uint8_t i_filters; /* 0x01: gauss 5 pixel (8,2,2,2,2)/16 0x02: gauss 5 pixel (8,1,1,1,1)/12 0x04: cartoon filter */ int i_timecode; /* ms */ int i_length; /* V,A,T: length of following data S: length of packet correl */} frame_header_t;/* FIXME Not sure of this one */typedef struct{ int i_version; vlc_fourcc_t i_video_fcc; vlc_fourcc_t i_audio_fcc; int i_audio_sample_rate; int i_audio_bits_per_sample; int i_audio_channels; int i_audio_compression_ratio; int i_audio_quality; int i_rtjpeg_quality; int i_rtjpeg_luma_filter; int i_rtjpeg_chroma_filter; int i_lavc_bitrate; int i_lavc_qmin; int i_lavc_qmax; int i_lavc_maxqdiff; int64_t i_seekable_offset; int64_t i_keyframe_adjust_offset;} extended_header_t;struct demux_sys_t{ header_t hdr; extended_header_t exh; int64_t i_pcr; es_out_id_t *p_es_video; int i_extra_f; uint8_t *p_extra_f; es_out_id_t *p_es_audio; /* index */ demux_index_t idx;};static int HeaderLoad( demux_t *, header_t *h );static int FrameHeaderLoad( demux_t *, frame_header_t *h );static int ExtendedHeaderLoad( demux_t *, extended_header_t *h );/***************************************************************************** * Open: initializes ES structures *****************************************************************************/static int Open( vlc_object_t * p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; uint8_t *p_peek; frame_header_t fh; vlc_bool_t b_extended; /* Check id */ if( stream_Peek( p_demux->s, &p_peek, 12 ) != 12 || ( strncmp( p_peek, "MythTVVideo", 11 ) && strncmp( p_peek, "NuppelVideo", 11 ) ) ) return VLC_EGENERIC; p_sys = malloc( sizeof( demux_sys_t ) ); memset( p_sys, 0, sizeof( demux_sys_t ) ); p_sys->p_es_video = NULL; p_sys->p_es_audio = NULL; p_sys->p_extra_f = NULL; p_sys->i_pcr = -1; demux_IndexInit( &p_sys->idx ); if( HeaderLoad( p_demux, &p_sys->hdr ) ) goto error; /* Load 'D' */ if( FrameHeaderLoad( p_demux, &fh ) || fh.i_type != 'D' ) goto error; if( fh.i_length > 0 ) { if( fh.i_compression == 'F' ) { /* ffmpeg extra data */ p_sys->i_extra_f = fh.i_length; p_sys->p_extra_f = malloc( fh.i_length ); if( stream_Read( p_demux->s, p_sys->p_extra_f, fh.i_length ) != fh.i_length ) goto error; } else { /* TODO handle rtjpeg */ msg_Warn( p_demux, "unsuported 'D' frame (c=%c)", fh.i_compression ); if( stream_Read( p_demux->s, NULL, fh.i_length ) != fh.i_length ) goto error; } } /* Check and load extented */ if( stream_Peek( p_demux->s, &p_peek, 1 ) != 1 ) goto error; if( p_peek[0] == 'X' ) { b_extended = VLC_TRUE; if( FrameHeaderLoad( p_demux, &fh ) ) goto error; if( fh.i_length != 512 ) goto error; if( ExtendedHeaderLoad( p_demux, &p_sys->exh ) ) goto error; } else { b_extended = VLC_FALSE; /* XXX: for now only file with extended chunk are supported * why: because else we need to have support for rtjpeg+stupid nuv shit */ msg_Err( p_demux, "incomplete NUV support (upload samples)" ); goto error; } /* Create audio/video (will work only with extended header and audio=mp3 */ if( p_sys->hdr.i_video_blocks != 0 ) { es_format_t fmt; es_format_Init( &fmt, VIDEO_ES, p_sys->exh.i_video_fcc ); fmt.video.i_width = p_sys->hdr.i_width; fmt.video.i_height = p_sys->hdr.i_height; fmt.i_extra = p_sys->i_extra_f; fmt.p_extra = p_sys->p_extra_f; p_sys->p_es_video = es_out_Add( p_demux->out, &fmt ); } if( p_sys->hdr.i_audio_blocks != 0 ) { es_format_t fmt; es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC('m','p','g','a') ); fmt.audio.i_rate = p_sys->exh.i_audio_sample_rate; fmt.audio.i_bitspersample = p_sys->exh.i_audio_bits_per_sample; p_sys->p_es_audio = es_out_Add( p_demux->out, &fmt ); } if( p_sys->hdr.i_text_blocks != 0 ) { msg_Warn( p_demux, "text not yet supported (upload samples)" ); } /* Fill p_demux fields */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; return VLC_SUCCESS;error: msg_Warn( p_demux, "cannot load Nuv file" ); free( p_sys ); return VLC_EGENERIC;}/***************************************************************************** * Close: frees unused data *****************************************************************************/static void Close( vlc_object_t * p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; if( p_sys->p_extra_f ) free( p_sys->p_extra_f ); demux_IndexClean( &p_sys->idx ); free( p_sys );}/***************************************************************************** * Demux: reads and demuxes data packets ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/static int Demux( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; frame_header_t fh; block_t *p_data; for( ;; ) { if( p_demux->b_die ) return -1; if( FrameHeaderLoad( p_demux, &fh ) ) return 0; if( fh.i_type == 'A' || fh.i_type == 'V' ) break; /* TODO add support for some block type */ if( fh.i_type != 'R' ) { stream_Read( p_demux->s, NULL, fh.i_length ); } } /* */ p_data = stream_Block( p_demux->s, fh.i_length ); p_data->i_dts = (int64_t)fh.i_timecode * 1000; p_data->i_pts = (fh.i_type == 'V') ? 0 : p_data->i_dts; /* */ demux_IndexAppend( &p_sys->idx, p_data->i_dts, stream_Tell(p_demux->s) ); /* */ if( p_data->i_dts > p_sys->i_pcr ) { p_sys->i_pcr = p_data->i_dts; es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr ); } if( fh.i_type == 'A' && p_sys->p_es_audio ) { if( fh.i_compression == '3' ) es_out_Send( p_demux->out, p_sys->p_es_audio, p_data ); else { msg_Dbg( p_demux, "unsupported compression %c for audio (upload samples)", fh.i_compression ); block_Release( p_data ); } } else if( fh.i_type == 'V' && p_sys->p_es_video ) { if( fh.i_compression >= '4' ) es_out_Send( p_demux->out, p_sys->p_es_video, p_data ); else { msg_Dbg( p_demux, "unsupported compression %c for video (upload samples)", fh.i_compression ); block_Release( p_data ); } } else { block_Release( p_data ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -