/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; if( !( p_block_in = stream_Block( p_demux->s, FLAC_PACKET_SIZE ) ) ) return 0; p_block_in->i_pts = p_block_in->i_dts = p_sys->b_start ? VLC_TS_0 : VLC_TS_INVALID; p_sys->b_start = false; while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) ) { while( p_block_out ) { block_t *p_next = p_block_out->p_next; p_block_out->p_next = NULL; if( p_sys->p_es == NULL ) { p_sys->p_packetizer->fmt_out.b_packetized = true; p_sys->p_packetizer->fmt_out.audio_replay_gain = p_sys->replay_gain; p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out); } p_sys->i_pts = p_block_out->i_dts - VLC_TS_0; /* Correct timestamp */ p_block_out->i_pts += p_sys->i_time_offset; p_block_out->i_dts += p_sys->i_time_offset; /* set PCR */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; } } return 1; }
static void ResetTime( demux_t *p_demux, int64_t i_time ) { demux_sys_t *p_sys = p_demux->p_sys; if( p_sys->ic->start_time == (int64_t)AV_NOPTS_VALUE || i_time < 0 ) i_time = VLC_TS_INVALID; else if( i_time == 0 ) i_time = 1; p_sys->i_pcr = i_time; for( int i = 0; i < p_sys->i_tk; i++ ) p_sys->tk_pcr[i] = i_time; if( i_time > VLC_TS_INVALID ) { es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time ); UpdateSeekPoint( p_demux, i_time ); } }
void ts_pmt_Del( demux_t *p_demux, ts_pmt_t *pmt ) { if( dvbpsi_decoder_present( pmt->handle ) ) dvbpsi_pmt_detach( pmt->handle ); dvbpsi_delete( pmt->handle ); for( int i=0; i<pmt->e_streams.i_size; i++ ) PIDRelease( p_demux, pmt->e_streams.p_elems[i] ); ARRAY_RESET( pmt->e_streams ); if( pmt->p_mgt ) PIDRelease( p_demux, pmt->p_mgt ); if( pmt->iod ) ODFree( pmt->iod ); for( int i=0; i<pmt->od.objects.i_size; i++ ) ODFree( pmt->od.objects.p_elems[i] ); ARRAY_RESET( pmt->od.objects ); if( pmt->i_number > -1 ) es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, pmt->i_number ); free( pmt ); }
static void *Thread(void *data) { demux_t *demux = data; demux_sys_t *sys = demux->p_sys; struct wl_display *display = sys->display; struct pollfd ufd[1]; unsigned interval = lroundf(CLOCK_FREQ / (sys->rate * 1000.f)); int canc = vlc_savecancel(); vlc_cleanup_push(cleanup_wl_display_read, display); ufd[0].fd = wl_display_get_fd(display); ufd[0].events = POLLIN; for (;;) { if (DisplayError(demux, display)) break; if (sys->es != NULL) { block_t *block = Shoot(demux); block->i_pts = block->i_dts = mdate(); es_out_Control(demux->out, ES_OUT_SET_PCR, block->i_pts); es_out_Send(demux->out, sys->es, block); } while (wl_display_prepare_read(display) != 0) wl_display_dispatch_pending(display); wl_display_flush(display); vlc_restorecancel(canc); while (poll(ufd, 1, interval) < 0); canc = vlc_savecancel(); wl_display_read_events(display); wl_display_dispatch_pending(display); } vlc_cleanup_pop(); vlc_restorecancel(canc); return NULL; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * 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; block_t *p_block; p_block = stream_Block( p_demux->s, CDG_FRAME_SIZE ); if( p_block == NULL ) { msg_Dbg( p_demux, "cannot read data, eof" ); return 0; } p_block->i_dts = p_block->i_pts = date_Increment( &p_sys->pts, 1 ); es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); return 1; }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; if( ( p_block_in = stream_Block( p_demux->s, H264_PACKET_SIZE ) ) == NULL ) { return 0; } /* m4v demuxer doesn't set pts/dts at all */ p_block_in->i_dts = 1; p_block_in->i_pts = 1; while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) ) { while( p_block_out ) { block_t *p_next = p_block_out->p_next; p_block_out->p_next = NULL; if( p_sys->p_es == NULL ) { p_sys->p_packetizer->fmt_out.b_packetized = VLC_TRUE; p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out); } es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_dts ); p_block_out->i_dts = p_sys->i_dts; p_block_out->i_pts = p_sys->i_dts; es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; p_sys->i_dts += (int64_t)((double)1000000.0 / p_sys->f_fps); } } return 1; }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; bool b_eof = !( p_block_in = stream_Block( p_demux->s, FLAC_PACKET_SIZE ) ); if ( p_block_in ) { p_block_in->i_pts = p_block_in->i_dts = p_sys->b_start ? VLC_TS_0 : VLC_TS_INVALID; p_sys->b_start = false; } while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, (p_block_in) ? &p_block_in : NULL )) ) { while( p_block_out ) { block_t *p_next = p_block_out->p_next; p_block_out->p_next = NULL; if( p_sys->p_es == NULL ) { p_sys->p_packetizer->fmt_out.b_packetized = true; p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out); } p_sys->i_pts = p_block_out->i_dts; /* set PCR */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; } } return !b_eof; }
/***************************************************************************** * 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; block_t *p_block; mtime_t i_pcr = date_Get( &p_sys->pcr ); /* Call the pace control */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + i_pcr ); if( p_sys->b_y4m ) { /* Skip the frame header */ /* Skip "FRAME" */ if( stream_Read( p_demux->s, NULL, 5 ) < 5 ) return 0; /* Find \n */ for( ;; ) { uint8_t b; if( stream_Read( p_demux->s, &b, 1 ) < 1 ) return 0; if( b == 0x0a ) break; } } if( ( p_block = stream_Block( p_demux->s, p_sys->frame_size ) ) == NULL ) { /* EOF */ return 0; } p_block->i_dts = p_block->i_pts = VLC_TS_0 + i_pcr; es_out_Send( p_demux->out, p_sys->p_es_video, p_block ); date_Increment( &p_sys->pcr, 1 ); return 1; }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; if( ( p_block_in = stream_Block( p_demux->s, MPGV_PACKET_SIZE ) ) == NULL ) { return 0; } if( p_sys->b_start ) { p_block_in->i_pts = p_block_in->i_dts = VLC_TS_0; } else { p_block_in->i_pts = p_block_in->i_dts = VLC_TS_INVALID; } while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) ) { p_sys->b_start = false; while( p_block_out ) { block_t *p_next = p_block_out->p_next; es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); p_block_out->p_next = NULL; es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; } } return 1; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * 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; block_t *p_block; /* set PCR */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time ); if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL ) { msg_Warn( p_demux, "cannot read data" ); return 0; } p_block->i_dts = p_block->i_pts = VLC_TS_0 + p_sys->i_time; es_out_Send( p_demux->out, p_sys->es, p_block ); p_sys->i_time += p_sys->i_frame_length; return 1; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * 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; block_t *p_block; const int64_t i_pos = stream_Tell( p_demux->s ); if( p_sys->i_data_size > 0 && i_pos >= p_sys->i_data_pos + p_sys->i_data_size ) { /* EOF */ return 0; } if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL ) { msg_Warn( p_demux, "cannot read data" ); return 0; } p_block->i_dts = p_block->i_pts = VLC_TS_0 + date_Get( &p_sys->pts ); /* set PCR */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts ); /* Do the channel reordering */ if( p_sys->i_chans_to_reorder ) aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer, p_sys->fmt.audio.i_channels, p_sys->pi_chan_table, p_sys->fmt.i_codec ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, p_sys->i_frame_samples ); return 1; }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; if( ( p_block_in = stream_Block( p_demux->s, M4A_PACKET_SIZE ) ) == NULL ) { return 0; } p_block_in->i_pts = p_block_in->i_dts = p_sys->b_start ? 1 : 0; p_sys->b_start = VLC_FALSE; while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) ) { while( p_block_out ) { block_t *p_next = p_block_out->p_next; if( p_sys->p_es == NULL ) { p_sys->p_packetizer->fmt_out.b_packetized = VLC_TRUE; p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out); } es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); p_block_out->p_next = NULL; es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; } } return 1; }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; bool b_eof = false; if( ( p_block_in = vlc_stream_Block( p_demux->s, MPGV_PACKET_SIZE ) ) == NULL ) { b_eof = true; } if( p_block_in ) { p_block_in->i_pts = p_block_in->i_dts = ( p_sys->b_start ) ? VLC_TS_0 : VLC_TS_INVALID; } while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, p_block_in ? &p_block_in : NULL )) ) { p_sys->b_start = false; while( p_block_out ) { block_t *p_next = p_block_out->p_next; es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); p_block_out->p_next = NULL; es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; } } return (b_eof) ? VLC_DEMUXER_EOF : VLC_DEMUXER_SUCCESS; }
void virtual_segment_c::ChangeSegment( matroska_segment_c * p_old, matroska_segment_c * p_new, mtime_t i_mk_start_time ) { size_t i, j; char *sub_lang = NULL, *aud_lang = NULL; for( i = 0; i < p_old->tracks.size(); i++) { mkv_track_t *p_tk = p_old->tracks[i]; es_format_t *p_ofmt = &p_tk->fmt; if( p_tk->p_es ) { bool state = false; es_out_Control( p_old->sys.demuxer.out, ES_OUT_GET_ES_STATE, p_tk->p_es, &state ); if( state ) { if( p_ofmt->i_cat == AUDIO_ES ) aud_lang = p_tk->fmt.psz_language; else if( p_ofmt->i_cat == SPU_ES ) sub_lang = p_tk->fmt.psz_language; } } } for( i = 0; i < p_new->tracks.size(); i++) { mkv_track_t *p_tk = p_new->tracks[i]; es_format_t *p_nfmt = &p_tk->fmt; /* Let's only do that for audio and video for now */ if( p_nfmt->i_cat == AUDIO_ES || p_nfmt->i_cat == VIDEO_ES ) { /* check for a similar elementary stream */ for( j = 0; j < p_old->tracks.size(); j++) { es_format_t * p_ofmt = &p_old->tracks[j]->fmt; if( !p_old->tracks[j]->p_es ) continue; if( ( p_nfmt->i_cat == p_ofmt->i_cat ) && ( p_nfmt->i_codec == p_ofmt->i_codec ) && ( p_nfmt->i_priority == p_ofmt->i_priority ) && ( p_nfmt->i_bitrate == p_ofmt->i_bitrate ) && ( p_nfmt->i_extra == p_ofmt->i_extra ) && ( p_nfmt->i_extra == 0 || !memcmp( p_nfmt->p_extra, p_ofmt->p_extra, p_nfmt->i_extra ) ) && !strcasecmp( p_nfmt->psz_language, p_ofmt->psz_language ) && ( ( p_nfmt->i_cat == AUDIO_ES && !memcmp( &p_nfmt->audio, &p_ofmt->audio, sizeof(audio_format_t) ) ) || ( p_nfmt->i_cat == VIDEO_ES && !memcmp( &p_nfmt->video, &p_ofmt->video, sizeof(video_format_t) ) ) ) ) { /* FIXME handle video palettes... */ msg_Warn( &p_old->sys.demuxer, "Reusing decoder of old track %zu for track %zu", j, i); p_tk->p_es = p_old->tracks[j]->p_es; p_old->tracks[j]->p_es = NULL; break; } } } p_tk->fmt.i_priority &= ~(0x10); if( ( sub_lang && p_nfmt->i_cat == SPU_ES && !strcasecmp(sub_lang, p_nfmt->psz_language) ) || ( aud_lang && p_nfmt->i_cat == AUDIO_ES && !strcasecmp(aud_lang, p_nfmt->psz_language) ) ) { msg_Warn( &p_old->sys.demuxer, "Since previous segment used lang %s forcing track %zu", p_nfmt->psz_language, i); p_tk->fmt.i_priority |= 0x10; p_tk->b_forced = true; } } p_new->Select( i_mk_start_time ); p_old->UnSelect(); }
static void *Thread (void *data) { demux_t *demux = data; demux_sys_t *sys = demux->p_sys; snd_pcm_t *pcm = sys->pcm; size_t bytes; int canc, val; canc = vlc_savecancel (); bytes = snd_pcm_frames_to_bytes (pcm, sys->period_size); val = snd_pcm_start (pcm); if (val) { msg_Err (demux, "cannot prepare device: %s", snd_strerror (val)); return NULL; } for (;;) { block_t *block = block_Alloc (bytes); if (unlikely(block == NULL)) break; /* Wait for data */ Poll (pcm, canc); /* Read data */ snd_pcm_sframes_t frames, delay; mtime_t pts; frames = snd_pcm_readi (pcm, block->p_buffer, sys->period_size); pts = mdate (); if (frames < 0) { if (frames == -EAGAIN) continue; val = snd_pcm_recover (pcm, frames, 1); if (val == 0) { msg_Warn (demux, "cannot read samples: %s", snd_strerror (frames)); continue; } msg_Err (demux, "cannot recover record stream: %s", snd_strerror (val)); DumpDeviceStatus (demux, pcm); break; } /* Compute time stamp */ if (snd_pcm_delay (pcm, &delay)) delay = 0; delay += frames; pts -= (CLOCK_FREQ * delay) / sys->rate; block->i_buffer = snd_pcm_frames_to_bytes (pcm, frames); block->i_nb_samples = frames; block->i_pts = pts; block->i_length = (CLOCK_FREQ * frames) / sys->rate; es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts); es_out_Send (demux->out, sys->es, block); } return NULL; }
int OpenDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; AVProbeData pd = { }; AVInputFormat *fmt = NULL; int64_t i_start_time = -1; bool b_can_seek; char *psz_url; const uint8_t *peek; int error; /* Init Probe data */ pd.buf_size = vlc_stream_Peek( p_demux->s, &peek, 2048 + 213 ); if( pd.buf_size <= 0 ) { msg_Warn( p_demux, "cannot peek" ); return VLC_EGENERIC; } pd.buf = malloc( pd.buf_size + AVPROBE_PADDING_SIZE ); if( unlikely(pd.buf == NULL) ) return VLC_ENOMEM; memcpy( pd.buf, peek, pd.buf_size ); memset( pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE ); if( p_demux->psz_file ) psz_url = strdup( p_demux->psz_file ); else { if( asprintf( &psz_url, "%s://%s", p_demux->psz_access, p_demux->psz_location ) == -1) psz_url = NULL; } if( psz_url != NULL ) msg_Dbg( p_demux, "trying url: %s", psz_url ); pd.filename = psz_url; vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_can_seek ); vlc_init_avformat(p_this); /* Guess format */ char *psz_format = var_InheritString( p_this, "avformat-format" ); if( psz_format ) { if( (fmt = av_find_input_format(psz_format)) ) msg_Dbg( p_demux, "forcing format: %s", fmt->name ); free( psz_format ); } if( fmt == NULL ) fmt = av_probe_input_format( &pd, 1 ); free( pd.buf ); if( fmt == NULL ) { msg_Dbg( p_demux, "couldn't guess format" ); free( psz_url ); return VLC_EGENERIC; } if( !p_demux->obj.force ) { static const char ppsz_blacklist[][16] = { /* Don't handle MPEG unless forced */ "mpeg", "vcd", "vob", "mpegts", /* libavformat's redirector won't work */ "redir", "sdp", /* Don't handle subtitles format */ "ass", "srt", "microdvd", /* No timestamps at all */ "hevc", "h264", "" }; for( int i = 0; *ppsz_blacklist[i]; i++ ) { if( !strcmp( fmt->name, ppsz_blacklist[i] ) ) { free( psz_url ); return VLC_EGENERIC; } } } /* Don't trigger false alarms on bin files */ if( !p_demux->obj.force && !strcmp( fmt->name, "psxstr" ) ) { int i_len; if( !p_demux->psz_file ) { free( psz_url ); return VLC_EGENERIC; } i_len = strlen( p_demux->psz_file ); if( i_len < 4 ) { free( psz_url ); return VLC_EGENERIC; } if( strcasecmp( &p_demux->psz_file[i_len - 4], ".str" ) && strcasecmp( &p_demux->psz_file[i_len - 4], ".xai" ) && strcasecmp( &p_demux->psz_file[i_len - 3], ".xa" ) ) { free( psz_url ); return VLC_EGENERIC; } } msg_Dbg( p_demux, "detected format: %s", fmt->name ); /* Fill p_demux fields */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = xmalloc( sizeof( demux_sys_t ) ); p_sys->ic = 0; p_sys->fmt = fmt; p_sys->i_tk = 0; p_sys->tk = NULL; p_sys->tk_pcr = NULL; p_sys->i_ssa_order = 0; TAB_INIT( p_sys->i_attachments, p_sys->attachments); p_sys->p_title = NULL; /* Create I/O wrapper */ unsigned char * p_io_buffer = av_malloc( AVFORMAT_IOBUFFER_SIZE ); if( !p_io_buffer ) { free( psz_url ); CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic = avformat_alloc_context(); if( !p_sys->ic ) { av_free( p_io_buffer ); free( psz_url ); CloseDemux( p_this ); return VLC_ENOMEM; } AVIOContext *pb = p_sys->ic->pb = avio_alloc_context( p_io_buffer, AVFORMAT_IOBUFFER_SIZE, 0, p_demux, IORead, NULL, IOSeek ); if( !pb ) { av_free( p_io_buffer ); free( psz_url ); CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic->pb->seekable = b_can_seek ? AVIO_SEEKABLE_NORMAL : 0; error = avformat_open_input(&p_sys->ic, psz_url, p_sys->fmt, NULL); if( error < 0 ) { msg_Err( p_demux, "Could not open %s: %s", psz_url, vlc_strerror_c(AVUNERROR(error)) ); av_free( p_io_buffer ); av_free( pb ); p_sys->ic = NULL; free( psz_url ); CloseDemux( p_this ); return VLC_EGENERIC; } free( psz_url ); char *psz_opts = var_InheritString( p_demux, "avformat-options" ); AVDictionary *options[p_sys->ic->nb_streams ? p_sys->ic->nb_streams : 1]; options[0] = NULL; unsigned int nb_streams = p_sys->ic->nb_streams; for (unsigned i = 1; i < nb_streams; i++) options[i] = NULL; if (psz_opts) { vlc_av_get_options(psz_opts, &options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_copy(&options[i], options[0], 0); } free(psz_opts); } vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */ error = avformat_find_stream_info( p_sys->ic, options ); /* FIXME: what if nb_streams change after that call? */ vlc_avcodec_unlock(); AVDictionaryEntry *t = NULL; while ((t = av_dict_get(options[0], "", t, AV_DICT_IGNORE_SUFFIX))) { msg_Err( p_demux, "Unknown option \"%s\"", t->key ); } av_dict_free(&options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_free(&options[i]); } if( error < 0 ) { msg_Warn( p_demux, "Could not find stream info: %s", vlc_strerror_c(AVUNERROR(error)) ); } for( unsigned i = 0; i < p_sys->ic->nb_streams; i++ ) { AVStream *s = p_sys->ic->streams[i]; const AVCodecParameters *cp = s->codecpar; es_out_id_t *es = NULL; es_format_t es_fmt; const char *psz_type = "unknown"; /* Do not use the cover art as a stream */ if( s->disposition == AV_DISPOSITION_ATTACHED_PIC ) { TAB_APPEND( p_sys->i_tk, p_sys->tk, NULL ); continue; } vlc_fourcc_t fcc = GetVlcFourcc( cp->codec_id ); switch( cp->codec_type ) { case AVMEDIA_TYPE_AUDIO: es_format_Init( &es_fmt, AUDIO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.i_bitrate = cp->bit_rate; es_fmt.audio.i_channels = cp->channels; es_fmt.audio.i_rate = cp->sample_rate; es_fmt.audio.i_bitspersample = cp->bits_per_coded_sample; es_fmt.audio.i_blockalign = cp->block_align; psz_type = "audio"; if(cp->codec_id == AV_CODEC_ID_AAC_LATM) { es_fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M'); es_fmt.b_packetized = false; } else if(cp->codec_id == AV_CODEC_ID_AAC && strstr(p_sys->fmt->long_name, "raw ADTS AAC")) { es_fmt.i_original_fourcc = VLC_FOURCC('A','D','T','S'); es_fmt.b_packetized = false; } break; case AVMEDIA_TYPE_VIDEO: es_format_Init( &es_fmt, VIDEO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.video.i_bits_per_pixel = cp->bits_per_coded_sample; /* Special case for raw video data */ if( cp->codec_id == AV_CODEC_ID_RAWVIDEO ) { msg_Dbg( p_demux, "raw video, pixel format: %i", cp->format ); if( GetVlcChroma( &es_fmt.video, cp->format ) != VLC_SUCCESS) { msg_Err( p_demux, "was unable to find a FourCC match for raw video" ); } else es_fmt.i_codec = es_fmt.video.i_chroma; } /* We need this for the h264 packetizer */ else if( cp->codec_id == AV_CODEC_ID_H264 && ( p_sys->fmt == av_find_input_format("flv") || p_sys->fmt == av_find_input_format("matroska") || p_sys->fmt == av_find_input_format("mp4") ) ) es_fmt.i_original_fourcc = VLC_FOURCC( 'a', 'v', 'c', '1' ); es_fmt.video.i_width = cp->width; es_fmt.video.i_height = cp->height; es_fmt.video.i_visible_width = es_fmt.video.i_width; es_fmt.video.i_visible_height = es_fmt.video.i_height; get_rotation(&es_fmt, s); # warning FIXME: implement palette transmission psz_type = "video"; es_fmt.video.i_frame_rate = s->codec->time_base.num; es_fmt.video.i_frame_rate_base = s->codec->time_base.den * __MAX( s->codec->ticks_per_frame, 1 ); es_fmt.video.i_sar_num = s->sample_aspect_ratio.num; if (s->sample_aspect_ratio.num > 0) es_fmt.video.i_sar_den = s->sample_aspect_ratio.den; else es_fmt.video.i_sar_den = 0; break; case AVMEDIA_TYPE_SUBTITLE: es_format_Init( &es_fmt, SPU_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); if( strncmp( p_sys->ic->iformat->name, "matroska", 8 ) == 0 && cp->codec_id == AV_CODEC_ID_DVD_SUBTITLE && cp->extradata != NULL && cp->extradata_size > 0 ) { char *psz_start; char *psz_buf = malloc( cp->extradata_size + 1); if( psz_buf != NULL ) { memcpy( psz_buf, cp->extradata , cp->extradata_size ); psz_buf[cp->extradata_size] = '\0'; psz_start = strstr( psz_buf, "size:" ); if( psz_start && vobsub_size_parse( psz_start, &es_fmt.subs.spu.i_original_frame_width, &es_fmt.subs.spu.i_original_frame_height ) == VLC_SUCCESS ) { msg_Dbg( p_demux, "original frame size: %dx%d", es_fmt.subs.spu.i_original_frame_width, es_fmt.subs.spu.i_original_frame_height ); } else { msg_Warn( p_demux, "reading original frame size failed" ); } psz_start = strstr( psz_buf, "palette:" ); if( psz_start && vobsub_palette_parse( psz_start, &es_fmt.subs.spu.palette[1] ) == VLC_SUCCESS ) { es_fmt.subs.spu.palette[0] = SPU_PALETTE_DEFINED; msg_Dbg( p_demux, "vobsub palette read" ); } else { msg_Warn( p_demux, "reading original palette failed" ); } free( psz_buf ); } } psz_type = "subtitle"; break; default: es_format_Init( &es_fmt, UNKNOWN_ES, 0 ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type == AVMEDIA_TYPE_ATTACHMENT ) { input_attachment_t *p_attachment; psz_type = "attachment"; if( cp->codec_id == AV_CODEC_ID_TTF ) { AVDictionaryEntry *filename = av_dict_get( s->metadata, "filename", NULL, 0 ); if( filename && filename->value ) { p_attachment = vlc_input_attachment_New( filename->value, "application/x-truetype-font", NULL, cp->extradata, (int)cp->extradata_size ); if( p_attachment ) TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); } } else msg_Warn( p_demux, "unsupported attachment type (%u) in avformat demux", cp->codec_id ); } else #endif { if( cp->codec_type == AVMEDIA_TYPE_DATA ) psz_type = "data"; msg_Warn( p_demux, "unsupported track type (%u:%u) in avformat demux", cp->codec_type, cp->codec_id ); } break; } AVDictionaryEntry *language = av_dict_get( s->metadata, "language", NULL, 0 ); if ( language && language->value ) es_fmt.psz_language = strdup( language->value ); if( s->disposition & AV_DISPOSITION_DEFAULT ) es_fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1000; #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type != AVMEDIA_TYPE_ATTACHMENT ) #endif if( cp->codec_type != AVMEDIA_TYPE_DATA ) { const bool b_ogg = !strcmp( p_sys->fmt->name, "ogg" ); const uint8_t *p_extra = cp->extradata; unsigned i_extra = cp->extradata_size; if( cp->codec_id == AV_CODEC_ID_THEORA && b_ogg ) { unsigned pi_size[3]; const void *pp_data[3]; unsigned i_count; for( i_count = 0; i_count < 3; i_count++ ) { if( i_extra < 2 ) break; pi_size[i_count] = GetWBE( p_extra ); pp_data[i_count] = &p_extra[2]; if( i_extra < pi_size[i_count] + 2 ) break; p_extra += 2 + pi_size[i_count]; i_extra -= 2 + pi_size[i_count]; } if( i_count > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, i_count ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_SPEEX && b_ogg ) { const uint8_t p_dummy_comment[] = { 0, 0, 0, 0, 0, 0, 0, 0, }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_OPUS ) { const uint8_t p_dummy_comment[] = { 'O', 'p', 'u', 's', 'T', 'a', 'g', 's', 0, 0, 0, 0, /* Vendor String length */ /* Vendor String */ 0, 0, 0, 0, /* User Comment List Length */ }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->extradata_size > 0 ) { es_fmt.p_extra = malloc( i_extra ); if( es_fmt.p_extra ) { es_fmt.i_extra = i_extra; memcpy( es_fmt.p_extra, p_extra, i_extra ); } } es = es_out_Add( p_demux->out, &es_fmt ); if( s->disposition & AV_DISPOSITION_DEFAULT ) es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, es ); es_format_Clean( &es_fmt ); msg_Dbg( p_demux, "adding es: %s codec = %4.4s (%d)", psz_type, (char*)&fcc, cp->codec_id ); } TAB_APPEND( p_sys->i_tk, p_sys->tk, es ); } p_sys->tk_pcr = xcalloc( p_sys->i_tk, sizeof(*p_sys->tk_pcr) ); if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) i_start_time = p_sys->ic->start_time * 1000000 / AV_TIME_BASE; msg_Dbg( p_demux, "AVFormat(%s %s) supported stream", AVPROVIDER(LIBAVFORMAT), LIBAVFORMAT_IDENT ); msg_Dbg( p_demux, " - format = %s (%s)", p_sys->fmt->name, p_sys->fmt->long_name ); msg_Dbg( p_demux, " - start time = %"PRId64, i_start_time ); msg_Dbg( p_demux, " - duration = %"PRId64, ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ? p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 ); if( p_sys->ic->nb_chapters > 0 ) { p_sys->p_title = vlc_input_title_New(); p_sys->p_title->i_length = p_sys->ic->duration * 1000000 / AV_TIME_BASE; } for( unsigned i = 0; i < p_sys->ic->nb_chapters; i++ ) { seekpoint_t *s = vlc_seekpoint_New(); AVDictionaryEntry *title = av_dict_get( p_sys->ic->metadata, "title", NULL, 0); if( title && title->value ) { s->psz_name = strdup( title->value ); EnsureUTF8( s->psz_name ); msg_Dbg( p_demux, " - chapter %d: %s", i, s->psz_name ); } s->i_time_offset = p_sys->ic->chapters[i]->start * 1000000 * p_sys->ic->chapters[i]->time_base.num / p_sys->ic->chapters[i]->time_base.den - (i_start_time != -1 ? i_start_time : 0 ); TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } ResetTime( p_demux, 0 ); return VLC_SUCCESS; }
static int ControlSetTime( demux_t *p_demux, int64_t i_time ) { demux_sys_t *p_sys = p_demux->p_sys; bool b_seekable; int i; /* */ vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable ); if( !b_seekable ) return VLC_EGENERIC; const mtime_t i_length = ControlGetLength( p_demux ); if( i_length <= 0 ) return VLC_EGENERIC; const uint64_t i_stream_size = stream_Size( p_demux->s ); if( i_stream_size <= p_sys->i_data_pos ) return VLC_EGENERIC; const double i_bytemicrorate = (double) i_length / (i_stream_size - p_sys->i_data_pos); if( i_bytemicrorate == 0 ) return VLC_EGENERIC; uint64_t i_lower = p_sys->i_data_pos; uint64_t i_upper = i_stream_size; uint64_t i_start_pos; assert( p_sys->i_seekpoint > 0 ); /* ReadMeta ensure at least (0,0) */ if( p_sys->i_seekpoint > 1 ) { /* lookup base offset */ for( i = p_sys->i_seekpoint-1; i >= 0; i-- ) { if( p_sys->seekpoint[i]->i_time_offset <= i_time ) break; } i_lower = p_sys->seekpoint[0]->i_byte_offset + p_sys->i_data_pos; if( i+1 < p_sys->i_seekpoint ) i_upper = p_sys->seekpoint[i+1]->i_byte_offset + p_sys->i_data_pos; i_start_pos = i_lower; } else { i_start_pos = i_time / i_bytemicrorate; } if( VLC_SUCCESS != vlc_stream_Seek( p_demux->s, i_start_pos ) ) return VLC_EGENERIC; int i_ret = RefineSeek( p_demux, i_time, i_bytemicrorate, i_lower, i_upper ); if( i_ret == VLC_SUCCESS ) { p_sys->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY; Reset( p_sys ); es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time ); } return i_ret; }
/***************************************************************************** * Demux: *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; AVPacket pkt; block_t *p_frame; int64_t i_start_time; /* Read a frame */ int i_av_ret = av_read_frame( p_sys->ic, &pkt ); if( i_av_ret ) { /* Avoid EOF if av_read_frame returns AVERROR(EAGAIN) */ if( i_av_ret == AVERROR(EAGAIN) ) return 1; return 0; } if( pkt.stream_index < 0 || pkt.stream_index >= p_sys->i_tk ) { av_packet_unref( &pkt ); return 1; } const AVStream *p_stream = p_sys->ic->streams[pkt.stream_index]; if( p_stream->time_base.den <= 0 ) { msg_Warn( p_demux, "Invalid time base for the stream %d", pkt.stream_index ); av_packet_unref( &pkt ); return 1; } if( p_stream->codecpar->codec_id == AV_CODEC_ID_SSA ) { p_frame = BuildSsaFrame( &pkt, p_sys->i_ssa_order++ ); if( !p_frame ) { av_packet_unref( &pkt ); return 1; } } else { if( ( p_frame = block_Alloc( pkt.size ) ) == NULL ) { av_packet_unref( &pkt ); return 0; } memcpy( p_frame->p_buffer, pkt.data, pkt.size ); } if( pkt.flags & AV_PKT_FLAG_KEY ) p_frame->i_flags |= BLOCK_FLAG_TYPE_I; /* Used to avoid timestamps overlow */ lldiv_t q; if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) { q = lldiv( p_sys->ic->start_time, AV_TIME_BASE); i_start_time = q.quot * CLOCK_FREQ + q.rem * CLOCK_FREQ / AV_TIME_BASE; } else i_start_time = 0; if( pkt.dts == (int64_t)AV_NOPTS_VALUE ) p_frame->i_dts = VLC_TS_INVALID; else { q = lldiv( pkt.dts, p_stream->time_base.den ); p_frame->i_dts = q.quot * CLOCK_FREQ * p_stream->time_base.num + q.rem * CLOCK_FREQ * p_stream->time_base.num / p_stream->time_base.den - i_start_time + VLC_TS_0; } if( pkt.pts == (int64_t)AV_NOPTS_VALUE ) p_frame->i_pts = VLC_TS_INVALID; else { q = lldiv( pkt.pts, p_stream->time_base.den ); p_frame->i_pts = q.quot * CLOCK_FREQ * p_stream->time_base.num + q.rem * CLOCK_FREQ * p_stream->time_base.num / p_stream->time_base.den - i_start_time + VLC_TS_0; } if( pkt.duration > 0 && p_frame->i_length <= 0 ) p_frame->i_length = pkt.duration * CLOCK_FREQ * p_stream->time_base.num / p_stream->time_base.den; /* Add here notoriously bugged file formats/samples */ if( !strcmp( p_sys->fmt->name, "flv" ) ) { /* FLV and video PTS */ if( p_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && pkt.dts != (int64_t)AV_NOPTS_VALUE && pkt.dts == pkt.pts ) p_frame->i_pts = VLC_TS_INVALID; /* Handle broken dts/pts increase with AAC. Duration is correct. * sky_the80s_aacplus.flv #8195 */ if( p_stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && p_stream->codecpar->codec_id == AV_CODEC_ID_AAC ) { if( p_sys->tk_pcr[pkt.stream_index] != VLC_TS_INVALID && p_sys->tk_pcr[pkt.stream_index] + p_frame->i_length > p_frame->i_dts ) { p_frame->i_dts = p_frame->i_pts = p_sys->tk_pcr[pkt.stream_index] + p_frame->i_length; } } } #ifdef AVFORMAT_DEBUG msg_Dbg( p_demux, "tk[%d] dts=%"PRId64" pts=%"PRId64, pkt.stream_index, p_frame->i_dts, p_frame->i_pts ); #endif if( p_frame->i_dts > VLC_TS_INVALID ) p_sys->tk_pcr[pkt.stream_index] = p_frame->i_dts; int64_t i_ts_max = INT64_MIN; for( int i = 0; i < p_sys->i_tk; i++ ) i_ts_max = __MAX( i_ts_max, p_sys->tk_pcr[i] ); int64_t i_ts_min = INT64_MAX; for( int i = 0; i < p_sys->i_tk; i++ ) { if( p_sys->tk_pcr[i] > VLC_TS_INVALID && p_sys->tk_pcr[i] + 10 * CLOCK_FREQ >= i_ts_max ) i_ts_min = __MIN( i_ts_min, p_sys->tk_pcr[i] ); } if( i_ts_min >= p_sys->i_pcr ) { p_sys->i_pcr = i_ts_min; es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr ); UpdateSeekPoint( p_demux, p_sys->i_pcr ); } if( p_sys->tk[pkt.stream_index] != NULL ) es_out_Send( p_demux->out, p_sys->tk[pkt.stream_index], p_frame ); else block_Release( p_frame ); av_packet_unref( &pkt ); return 1; }
int avformat_OpenDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; AVInputFormat *fmt = NULL; vlc_tick_t i_start_time = VLC_TICK_INVALID; bool b_can_seek; const char *psz_url; int error; if( p_demux->psz_filepath ) psz_url = p_demux->psz_filepath; else psz_url = p_demux->psz_url; if( avformat_ProbeDemux( p_this, &fmt, psz_url ) != VLC_SUCCESS ) return VLC_EGENERIC; vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_can_seek ); /* Fill p_demux fields */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->ic = 0; p_sys->fmt = fmt; p_sys->tracks = NULL; p_sys->i_ssa_order = 0; TAB_INIT( p_sys->i_attachments, p_sys->attachments); p_sys->p_title = NULL; p_sys->i_seekpoint = 0; p_sys->i_update = 0; /* Create I/O wrapper */ unsigned char * p_io_buffer = av_malloc( AVFORMAT_IOBUFFER_SIZE ); if( !p_io_buffer ) { avformat_CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic = avformat_alloc_context(); if( !p_sys->ic ) { av_free( p_io_buffer ); avformat_CloseDemux( p_this ); return VLC_ENOMEM; } AVIOContext *pb = p_sys->ic->pb = avio_alloc_context( p_io_buffer, AVFORMAT_IOBUFFER_SIZE, 0, p_demux, IORead, NULL, IOSeek ); if( !pb ) { av_free( p_io_buffer ); avformat_CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic->pb->seekable = b_can_seek ? AVIO_SEEKABLE_NORMAL : 0; error = avformat_open_input(&p_sys->ic, psz_url, p_sys->fmt, NULL); if( error < 0 ) { msg_Err( p_demux, "Could not open %s: %s", psz_url, vlc_strerror_c(AVUNERROR(error)) ); av_free( pb->buffer ); av_free( pb ); p_sys->ic = NULL; avformat_CloseDemux( p_this ); return VLC_EGENERIC; } char *psz_opts = var_InheritString( p_demux, "avformat-options" ); unsigned nb_streams = p_sys->ic->nb_streams; AVDictionary *options[nb_streams ? nb_streams : 1]; options[0] = NULL; for (unsigned i = 1; i < nb_streams; i++) options[i] = NULL; if (psz_opts) { vlc_av_get_options(psz_opts, &options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_copy(&options[i], options[0], 0); } free(psz_opts); } vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */ error = avformat_find_stream_info( p_sys->ic, options ); vlc_avcodec_unlock(); AVDictionaryEntry *t = NULL; while ((t = av_dict_get(options[0], "", t, AV_DICT_IGNORE_SUFFIX))) { msg_Err( p_demux, "Unknown option \"%s\"", t->key ); } av_dict_free(&options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_free(&options[i]); } nb_streams = p_sys->ic->nb_streams; /* it may have changed */ if( !nb_streams ) { msg_Err( p_demux, "No streams found"); avformat_CloseDemux( p_this ); return VLC_EGENERIC; } p_sys->tracks = calloc( nb_streams, sizeof(*p_sys->tracks) ); if( !p_sys->tracks ) { avformat_CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->i_tracks = nb_streams; if( error < 0 ) { msg_Warn( p_demux, "Could not find stream info: %s", vlc_strerror_c(AVUNERROR(error)) ); } for( unsigned i = 0; i < nb_streams; i++ ) { struct avformat_track_s *p_track = &p_sys->tracks[i]; AVStream *s = p_sys->ic->streams[i]; const AVCodecParameters *cp = s->codecpar; es_format_t es_fmt; const char *psz_type = "unknown"; /* Do not use the cover art as a stream */ if( s->disposition == AV_DISPOSITION_ATTACHED_PIC ) continue; vlc_fourcc_t fcc = GetVlcFourcc( cp->codec_id ); switch( cp->codec_type ) { case AVMEDIA_TYPE_AUDIO: es_format_Init( &es_fmt, AUDIO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.i_bitrate = cp->bit_rate; es_fmt.audio.i_channels = cp->channels; es_fmt.audio.i_rate = cp->sample_rate; es_fmt.audio.i_bitspersample = cp->bits_per_coded_sample; es_fmt.audio.i_blockalign = cp->block_align; psz_type = "audio"; if(cp->codec_id == AV_CODEC_ID_AAC_LATM) { es_fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M'); es_fmt.b_packetized = false; } else if(cp->codec_id == AV_CODEC_ID_AAC && p_sys->fmt->long_name && strstr(p_sys->fmt->long_name, "raw ADTS AAC")) { es_fmt.i_original_fourcc = VLC_FOURCC('A','D','T','S'); es_fmt.b_packetized = false; } break; case AVMEDIA_TYPE_VIDEO: es_format_Init( &es_fmt, VIDEO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.video.i_bits_per_pixel = cp->bits_per_coded_sample; /* Special case for raw video data */ if( cp->codec_id == AV_CODEC_ID_RAWVIDEO ) { msg_Dbg( p_demux, "raw video, pixel format: %i", cp->format ); if( GetVlcChroma( &es_fmt.video, cp->format ) != VLC_SUCCESS) { msg_Err( p_demux, "was unable to find a FourCC match for raw video" ); } else es_fmt.i_codec = es_fmt.video.i_chroma; } /* We need this for the h264 packetizer */ else if( cp->codec_id == AV_CODEC_ID_H264 && ( p_sys->fmt == av_find_input_format("flv") || p_sys->fmt == av_find_input_format("matroska") || p_sys->fmt == av_find_input_format("mp4") ) ) es_fmt.i_original_fourcc = VLC_FOURCC( 'a', 'v', 'c', '1' ); es_fmt.video.i_width = cp->width; es_fmt.video.i_height = cp->height; es_fmt.video.i_visible_width = es_fmt.video.i_width; es_fmt.video.i_visible_height = es_fmt.video.i_height; get_rotation(&es_fmt, s); # warning FIXME: implement palette transmission psz_type = "video"; AVRational rate; #if (LIBAVUTIL_VERSION_MICRO < 100) /* libav */ # if (LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 20, 0)) rate.num = s->time_base.num; rate.den = s->time_base.den; # else rate.num = s->codec->time_base.num; rate.den = s->codec->time_base.den; # endif rate.den *= __MAX( s->codec->ticks_per_frame, 1 ); #else /* ffmpeg */ rate = av_guess_frame_rate( p_sys->ic, s, NULL ); #endif if( rate.den && rate.num ) { es_fmt.video.i_frame_rate = rate.num; es_fmt.video.i_frame_rate_base = rate.den; } AVRational ar; #if (LIBAVUTIL_VERSION_MICRO < 100) /* libav */ ar.num = s->sample_aspect_ratio.num; ar.den = s->sample_aspect_ratio.den; #else ar = av_guess_sample_aspect_ratio( p_sys->ic, s, NULL ); #endif if( ar.num && ar.den ) { es_fmt.video.i_sar_den = ar.den; es_fmt.video.i_sar_num = ar.num; } break; case AVMEDIA_TYPE_SUBTITLE: es_format_Init( &es_fmt, SPU_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); if( strncmp( p_sys->ic->iformat->name, "matroska", 8 ) == 0 && cp->codec_id == AV_CODEC_ID_DVD_SUBTITLE && cp->extradata != NULL && cp->extradata_size > 0 ) { char *psz_start; char *psz_buf = malloc( cp->extradata_size + 1); if( psz_buf != NULL ) { memcpy( psz_buf, cp->extradata , cp->extradata_size ); psz_buf[cp->extradata_size] = '\0'; psz_start = strstr( psz_buf, "size:" ); if( psz_start && vobsub_size_parse( psz_start, &es_fmt.subs.spu.i_original_frame_width, &es_fmt.subs.spu.i_original_frame_height ) == VLC_SUCCESS ) { msg_Dbg( p_demux, "original frame size: %dx%d", es_fmt.subs.spu.i_original_frame_width, es_fmt.subs.spu.i_original_frame_height ); } else { msg_Warn( p_demux, "reading original frame size failed" ); } psz_start = strstr( psz_buf, "palette:" ); if( psz_start && vobsub_palette_parse( psz_start, &es_fmt.subs.spu.palette[1] ) == VLC_SUCCESS ) { es_fmt.subs.spu.palette[0] = SPU_PALETTE_DEFINED; msg_Dbg( p_demux, "vobsub palette read" ); } else { msg_Warn( p_demux, "reading original palette failed" ); } free( psz_buf ); } } else if( cp->codec_id == AV_CODEC_ID_DVB_SUBTITLE && cp->extradata_size > 3 ) { es_fmt.subs.dvb.i_id = GetWBE( cp->extradata ) | (GetWBE( cp->extradata + 2 ) << 16); } else if( cp->codec_id == AV_CODEC_ID_MOV_TEXT ) { if( cp->extradata_size && (es_fmt.p_extra = malloc(cp->extradata_size)) ) { memcpy( es_fmt.p_extra, cp->extradata, cp->extradata_size ); es_fmt.i_extra = cp->extradata_size; } } psz_type = "subtitle"; break; default: es_format_Init( &es_fmt, UNKNOWN_ES, 0 ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type == AVMEDIA_TYPE_ATTACHMENT ) { input_attachment_t *p_attachment; psz_type = "attachment"; if( cp->codec_id == AV_CODEC_ID_TTF ) { AVDictionaryEntry *filename = av_dict_get( s->metadata, "filename", NULL, 0 ); if( filename && filename->value ) { p_attachment = vlc_input_attachment_New( filename->value, "application/x-truetype-font", NULL, cp->extradata, (int)cp->extradata_size ); if( p_attachment ) TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); } } else msg_Warn( p_demux, "unsupported attachment type (%u) in avformat demux", cp->codec_id ); } else #endif { if( cp->codec_type == AVMEDIA_TYPE_DATA ) psz_type = "data"; msg_Warn( p_demux, "unsupported track type (%u:%u) in avformat demux", cp->codec_type, cp->codec_id ); } break; } AVDictionaryEntry *language = av_dict_get( s->metadata, "language", NULL, 0 ); if ( language && language->value ) es_fmt.psz_language = strdup( language->value ); if( s->disposition & AV_DISPOSITION_DEFAULT ) es_fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1000; #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type != AVMEDIA_TYPE_ATTACHMENT ) #endif if( cp->codec_type != AVMEDIA_TYPE_DATA ) { const bool b_ogg = !strcmp( p_sys->fmt->name, "ogg" ); const uint8_t *p_extra = cp->extradata; unsigned i_extra = cp->extradata_size; if( cp->codec_id == AV_CODEC_ID_THEORA && b_ogg ) { unsigned pi_size[3]; const void *pp_data[3]; unsigned i_count; for( i_count = 0; i_count < 3; i_count++ ) { if( i_extra < 2 ) break; pi_size[i_count] = GetWBE( p_extra ); pp_data[i_count] = &p_extra[2]; if( i_extra < pi_size[i_count] + 2 ) break; p_extra += 2 + pi_size[i_count]; i_extra -= 2 + pi_size[i_count]; } if( i_count > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, i_count ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_SPEEX && b_ogg ) { const uint8_t p_dummy_comment[] = { 0, 0, 0, 0, 0, 0, 0, 0, }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_OPUS ) { const uint8_t p_dummy_comment[] = { 'O', 'p', 'u', 's', 'T', 'a', 'g', 's', 0, 0, 0, 0, /* Vendor String length */ /* Vendor String */ 0, 0, 0, 0, /* User Comment List Length */ }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->extradata_size > 0 && !es_fmt.i_extra ) { es_fmt.p_extra = malloc( i_extra ); if( es_fmt.p_extra ) { es_fmt.i_extra = i_extra; memcpy( es_fmt.p_extra, p_extra, i_extra ); } } p_track->p_es = es_out_Add( p_demux->out, &es_fmt ); if( p_track->p_es && (s->disposition & AV_DISPOSITION_DEFAULT) ) es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, p_track->p_es ); msg_Dbg( p_demux, "adding es: %s codec = %4.4s (%d)", psz_type, (char*)&fcc, cp->codec_id ); } es_format_Clean( &es_fmt ); } if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) i_start_time = FROM_AV_TS(p_sys->ic->start_time); msg_Dbg( p_demux, "AVFormat(%s %s) supported stream", AVPROVIDER(LIBAVFORMAT), LIBAVFORMAT_IDENT ); msg_Dbg( p_demux, " - format = %s (%s)", p_sys->fmt->name, p_sys->fmt->long_name ); msg_Dbg( p_demux, " - start time = %"PRId64, i_start_time ); msg_Dbg( p_demux, " - duration = %"PRId64, ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ? FROM_AV_TS(p_sys->ic->duration) : -1 ); if( p_sys->ic->nb_chapters > 0 ) { p_sys->p_title = vlc_input_title_New(); p_sys->p_title->i_length = FROM_AV_TS(p_sys->ic->duration); } for( unsigned i = 0; i < p_sys->ic->nb_chapters; i++ ) { seekpoint_t *s = vlc_seekpoint_New(); AVDictionaryEntry *title = av_dict_get( p_sys->ic->metadata, "title", NULL, 0); if( title && title->value ) { s->psz_name = strdup( title->value ); EnsureUTF8( s->psz_name ); msg_Dbg( p_demux, " - chapter %d: %s", i, s->psz_name ); } s->i_time_offset = vlc_tick_from_samples( p_sys->ic->chapters[i]->start * p_sys->ic->chapters[i]->time_base.num, p_sys->ic->chapters[i]->time_base.den ) - (i_start_time != VLC_TICK_INVALID ? i_start_time : 0 ); TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } ResetTime( p_demux, 0 ); return VLC_SUCCESS; }
/** * Processing callback */ static void Demux (void *opaque) { demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; xcb_connection_t *conn = sys->conn; /* Determine capture region */ xcb_get_geometry_cookie_t gc; xcb_query_pointer_cookie_t qc; gc = xcb_get_geometry (conn, sys->window); if (sys->follow_mouse) qc = xcb_query_pointer (conn, sys->window); xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); if (geo == NULL) { msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, sys->window); discard: if (sys->follow_mouse) xcb_discard_reply (conn, gc.sequence); return; } int w = sys->w; int h = sys->h; int x, y; if (sys->follow_mouse) { xcb_query_pointer_reply_t *ptr = xcb_query_pointer_reply (conn, qc, NULL); if (ptr == NULL) { free (geo); return; } if (w == 0 || w > geo->width) w = geo->width; x = ptr->win_x; if (x < w / 2) x = 0; else if (x >= (int)geo->width - (w / 2)) x = geo->width - w; else x -= w / 2; if (h == 0 || h > geo->height) h = geo->height; y = ptr->win_y; if (y < h / 2) y = 0; else if (y >= (int)geo->height - (h / 2)) y = geo->height - h; else y -= h / 2; } else { int max; x = sys->x; max = (int)geo->width - x; if (max <= 0) goto discard; if (w == 0 || w > max) w = max; y = sys->y; max = (int)geo->height - y; if (max <= 0) goto discard; if (h == 0 || h > max) h = max; } /* Update elementary stream format (if needed) */ if (w != sys->cur_w || h != sys->cur_h) { if (sys->es != NULL) es_out_Del (demux->out, sys->es); /* Update composite pixmap */ if (sys->window != geo->root) { xcb_free_pixmap (conn, sys->pixmap); /* no-op first time */ xcb_composite_name_window_pixmap (conn, sys->window, sys->pixmap); xcb_create_pixmap (conn, geo->depth, sys->pixmap, geo->root, geo->width, geo->height); } sys->es = InitES (demux, w, h, geo->depth, &sys->bpp); if (sys->es != NULL) { sys->cur_w = w; sys->cur_h = h; sys->bpp /= 8; /* bits -> bytes */ } } /* Capture screen */ xcb_drawable_t drawable = (sys->window != geo->root) ? sys->pixmap : sys->window; free (geo); block_t *block = NULL; #if HAVE_SYS_SHM_H if (sys->shm) { /* Capture screen through shared memory */ size_t size = w * h * sys->bpp; int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); if (id == -1) /* XXX: fallback */ { msg_Err (demux, "shared memory allocation error: %m"); goto noshm; } /* Attach the segment to X and capture */ xcb_shm_get_image_reply_t *img; xcb_shm_get_image_cookie_t ck; xcb_shm_attach (conn, sys->segment, id, 0 /* read/write */); ck = xcb_shm_get_image (conn, drawable, x, y, w, h, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, sys->segment, 0); xcb_shm_detach (conn, sys->segment); img = xcb_shm_get_image_reply (conn, ck, NULL); xcb_flush (conn); /* ensure eventual detach */ if (img == NULL) { shmctl (id, IPC_RMID, 0); goto noshm; } free (img); /* Attach the segment to VLC */ void *shm = shmat (id, NULL, 0 /* read/write */); shmctl (id, IPC_RMID, 0); if (-1 == (intptr_t)shm) { msg_Err (demux, "shared memory attachment error: %m"); return; } block = block_shm_Alloc (shm, size); if (unlikely(block == NULL)) shmdt (shm); } noshm: #endif if (block == NULL) { /* Capture screen through socket (fallback) */ xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable, x, y, w, h, ~0), NULL); if (img == NULL) return; uint8_t *data = xcb_get_image_data (img); size_t datalen = xcb_get_image_data_length (img); block = block_heap_Alloc (img, data + datalen - (uint8_t *)img); if (block == NULL) return; block->p_buffer = data; block->i_buffer = datalen; } /* Send block - zero copy */ if (sys->es != NULL) { block->i_pts = block->i_dts = mdate (); es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts); es_out_Send (demux->out, sys->es, block); } }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; /* Align stream */ int64_t i_pos = stream_Tell( p_demux->s ); if( i_pos % 2 ) stream_Read( p_demux->s, NULL, 1 ); if( !( p_block_in = stream_Block( p_demux->s, A52_PACKET_SIZE ) ) ) { return 0; } if( !p_sys->b_big_endian && p_block_in->i_buffer ) { /* Convert to big endian */ #ifdef HAVE_SWAB swab(p_block_in->p_buffer, p_block_in->p_buffer, p_block_in->i_buffer); #else int i; byte_t *p_tmp, tmp; p_tmp = p_block_in->p_buffer; for( i = p_block_in->i_buffer / 2 ; i-- ; ) { tmp = p_tmp[0]; p_tmp[0] = p_tmp[1]; p_tmp[1] = tmp; p_tmp += 2; } #endif } if( p_sys->b_start ) p_block_in->i_pts = p_block_in->i_dts = 1; else p_block_in->i_pts = p_block_in->i_dts = 0; while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) ) { p_sys->b_start = VLC_FALSE; while( p_block_out ) { block_t *p_next = p_block_out->p_next; /* We assume a constant bitrate */ if( p_block_out->i_length ) { p_sys->i_mux_rate = p_block_out->i_buffer * I64C(1000000)/p_block_out->i_length; } /* set PCR */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); p_block_out = p_next; } } return 1; }
static int ControlSetTime( demux_t *p_demux, int64_t i_time ) { demux_sys_t *p_sys = p_demux->p_sys; int64_t i_delta_time; bool b_seekable; int i; /* */ stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable ); if( !b_seekable ) return VLC_EGENERIC; /* */ assert( p_sys->i_seekpoint > 0 ); /* ReadMeta ensure at least (0,0) */ for( i = p_sys->i_seekpoint-1; i >= 0; i-- ) { if( p_sys->seekpoint[i]->i_time_offset <= i_time ) break; } i_delta_time = i_time - p_sys->seekpoint[i]->i_time_offset; /* XXX We do exact seek if it's not too far away(45s) */ if( i_delta_time < 45*INT64_C(1000000) ) { if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos ) ) return VLC_EGENERIC; p_sys->i_time_offset = p_sys->seekpoint[i]->i_time_offset - p_sys->i_pts; p_sys->i_pts_start = p_sys->i_pts+i_delta_time; es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_sys->i_pts_start + p_sys->i_time_offset ); } else { int64_t i_delta_offset; int64_t i_next_time; int64_t i_next_offset; if( i+1 < p_sys->i_seekpoint ) { i_next_time = p_sys->seekpoint[i+1]->i_time_offset; i_next_offset = p_sys->seekpoint[i+1]->i_byte_offset; } else { i_next_time = p_sys->i_length; i_next_offset = stream_Size(p_demux->s)-p_sys->i_data_pos; } i_delta_offset = 0; if( i_next_time-p_sys->seekpoint[i]->i_time_offset > 0 ) i_delta_offset = (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) * i_delta_time / (i_next_time-p_sys->seekpoint[i]->i_time_offset); if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos + i_delta_offset ) ) return VLC_EGENERIC; p_sys->i_pts_start = p_sys->i_pts; p_sys->i_time_offset = (p_sys->seekpoint[i]->i_time_offset+i_delta_time) - p_sys->i_pts; } return VLC_SUCCESS; }
/***************************************************************************** * 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; block_t *p_block_in, *p_block_out; if( ( p_block_in = stream_Block( p_demux->s, H26X_PACKET_SIZE ) ) == NULL ) { return 0; } while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) ) { while( p_block_out ) { block_t *p_next = p_block_out->p_next; p_block_out->p_next = NULL; p_block_in->i_dts = date_Get( &p_sys->dts ); p_block_in->i_pts = VLC_TS_INVALID; if( p_sys->p_es == NULL ) { p_sys->p_packetizer->fmt_out.b_packetized = true; p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out ); if( !p_sys->p_es ) return VLC_DEMUXER_EOF; } /* h264 packetizer does merge multiple NAL into AU, but slice flag persists */ bool frame = p_block_out->i_flags & BLOCK_FLAG_TYPE_MASK; es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); if( frame ) { if( !p_sys->frame_rate_den ) { /* Use packetizer's one */ if( p_sys->p_packetizer->fmt_out.video.i_frame_rate_base ) { p_sys->frame_rate_num = p_sys->p_packetizer->fmt_out.video.i_frame_rate; p_sys->frame_rate_den = p_sys->p_packetizer->fmt_out.video.i_frame_rate_base; } else { p_sys->frame_rate_num = 25000; p_sys->frame_rate_den = 1000; } date_Init( &p_sys->dts, p_sys->frame_rate_num, p_sys->frame_rate_den ); date_Set( &p_sys->dts, VLC_TS_0 ); msg_Dbg( p_demux, "using %.2f fps", (double) p_sys->frame_rate_num / p_sys->frame_rate_den ); } es_out_Control( p_demux->out, ES_OUT_SET_PCR, date_Get( &p_sys->dts ) ); date_Increment( &p_sys->dts, 1 ); } p_block_out = p_next; } } return 1; }
int Demux() { if ( !m_enabled ) return demux_Demux( p_demux->p_next ); /* The CC sout is not pacing, so we pace here */ int pace = p_renderer->pf_pace( p_renderer->p_opaque ); switch (pace) { case CC_PACE_ERR: return VLC_DEMUXER_EGENERIC; case CC_PACE_ERR_RETRY: { /* Seek back to started position */ seekBack(m_start_time, m_start_pos); resetDemuxEof(); p_renderer->pf_send_input_event( p_renderer->p_opaque, CC_INPUT_EVENT_RETRY, cc_input_arg{false} ); break; } case CC_PACE_OK_WAIT: /* Yeld: return to let the input thread doing controls */ return VLC_DEMUXER_SUCCESS; case CC_PACE_OK: case CC_PACE_OK_ENDED: break; default: vlc_assert_unreachable(); } int ret = VLC_DEMUXER_SUCCESS; if( !m_demux_eof ) { ret = demux_Demux( p_demux->p_next ); if( ret != VLC_DEMUXER_EGENERIC && ( m_start_time < 0 || m_start_pos < 0.0f ) ) initTimes(); if( ret == VLC_DEMUXER_EOF ) m_demux_eof = true; } if( m_demux_eof ) { /* Signal EOF to the sout when the es_out is empty (so when the * DecoderThread fifo are empty) */ bool b_empty; es_out_Control( p_demux->p_next->out, ES_OUT_GET_EMPTY, &b_empty ); if( b_empty ) p_renderer->pf_send_input_event( p_renderer->p_opaque, CC_INPUT_EVENT_EOF, cc_input_arg{ true } ); /* Don't return EOF until the chromecast is not EOF. This allows * this demux filter to have more controls over the sout. Indeed, * we still can seek or change tracks when the input is EOF and we * should continue to handle CC errors. */ ret = pace == CC_PACE_OK ? VLC_DEMUXER_SUCCESS : VLC_DEMUXER_EOF; } return ret; }
/** * Control callback */ static int Control (demux_t *demux, int query, va_list args) { demux_sys_t *p_sys = demux->p_sys; switch (query) { case DEMUX_GET_POSITION: { float *v = va_arg (args, float *); *v = 0.; return VLC_SUCCESS; } case DEMUX_GET_LENGTH: case DEMUX_GET_TIME: { int64_t *v = va_arg (args, int64_t *); *v = 0; return VLC_SUCCESS; } /* TODO: get title info -> crawl visible windows */ case DEMUX_GET_PTS_DELAY: { int64_t *v = va_arg (args, int64_t *); *v = var_GetInteger (demux, "screen-caching") * UINT64_C(1000); return VLC_SUCCESS; } case DEMUX_CAN_PAUSE: { bool *v = (bool*)va_arg( args, bool * ); *v = true; return VLC_SUCCESS; } case DEMUX_SET_PAUSE_STATE: { bool pausing = va_arg (args, int); if (!pausing) { vlc_mutex_lock (&p_sys->lock); p_sys->pts = VLC_TS_INVALID; es_out_Control (demux->out, ES_OUT_RESET_PCR); vlc_mutex_unlock (&p_sys->lock); } vlc_timer_schedule (p_sys->timer, false, pausing ? 0 : 1, p_sys->interval); return VLC_SUCCESS; } case DEMUX_CAN_CONTROL_PACE: case DEMUX_CAN_CONTROL_RATE: case DEMUX_CAN_SEEK: { bool *v = (bool*)va_arg( args, bool * ); *v = false; return VLC_SUCCESS; } } return VLC_EGENERIC; }
/** * Processing callback */ static void Demux (void *data) { demux_t *demux = data; demux_sys_t *p_sys = demux->p_sys; xcb_connection_t *conn = p_sys->conn; /* Update capture region (if needed) */ xcb_get_geometry_cookie_t gc = xcb_get_geometry (conn, p_sys->window); int16_t x = p_sys->x, y = p_sys->y; xcb_translate_coordinates_cookie_t tc; if (p_sys->window != p_sys->root) tc = xcb_translate_coordinates (conn, p_sys->window, p_sys->root, x, y); xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); if (geo == NULL) { msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, p_sys->window); return; } uint16_t w = geo->width - x; uint16_t h = geo->height - y; free (geo); if (p_sys->w > 0 && p_sys->w < w) w = p_sys->w; if (p_sys->h > 0 && p_sys->h < h) h = p_sys->h; if (p_sys->window != p_sys->root) { xcb_translate_coordinates_reply_t *coords = xcb_translate_coordinates_reply (conn, tc, NULL); if (coords == NULL) return; x = coords->dst_x; y = coords->dst_y; free (coords); } xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, p_sys->root, x, y, w, h, ~0), NULL); if (img == NULL) return; /* Send block - zero copy */ block_t *block = block_heap_Alloc (img, xcb_get_image_data (img), xcb_get_image_data_length (img)); if (block == NULL) return; vlc_mutex_lock (&p_sys->lock); if (w != p_sys->fmt.video.i_visible_width || h != p_sys->fmt.video.i_visible_height) { if (p_sys->es != NULL) es_out_Del (demux->out, p_sys->es); p_sys->fmt.video.i_visible_width = p_sys->fmt.video.i_width = w; p_sys->fmt.video.i_visible_height = p_sys->fmt.video.i_height = h; p_sys->es = es_out_Add (demux->out, &p_sys->fmt); } /* Capture screen */ if (p_sys->es != NULL) { if (p_sys->pts == VLC_TS_INVALID) p_sys->pts = mdate (); block->i_pts = block->i_dts = p_sys->pts; es_out_Control (demux->out, ES_OUT_SET_PCR, p_sys->pts); es_out_Send (demux->out, p_sys->es, block); p_sys->pts += p_sys->interval; } vlc_mutex_unlock (&p_sys->lock); }
/** * Processing callback */ static void Demux (void *data) { demux_t *demux = data; demux_sys_t *sys = demux->p_sys; xcb_connection_t *conn = sys->conn; /* Determine capture region */ xcb_get_geometry_cookie_t gc; xcb_query_pointer_cookie_t qc; gc = xcb_get_geometry (conn, sys->window); if (sys->follow_mouse) qc = xcb_query_pointer (conn, sys->window); xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); if (geo == NULL) { msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, sys->window); discard: if (sys->follow_mouse) xcb_discard_reply (conn, gc.sequence); return; } int w = sys->w; int h = sys->h; int x, y; if (sys->follow_mouse) { xcb_query_pointer_reply_t *ptr = xcb_query_pointer_reply (conn, qc, NULL); if (ptr == NULL) { free (geo); return; } if (w == 0 || w > geo->width) w = geo->width; x = ptr->win_x; if (x < w / 2) x = 0; else if (x >= (int)geo->width - (w / 2)) x = geo->width - w; else x -= w / 2; if (h == 0 || h > geo->height) h = geo->height; y = ptr->win_y; if (y < h / 2) y = 0; else if (y >= (int)geo->height - (h / 2)) y = geo->height - h; else y -= h / 2; } else { int max; x = sys->x; max = (int)geo->width - x; if (max <= 0) goto discard; if (w == 0 || w > max) w = max; y = sys->y; max = (int)geo->height - y; if (max <= 0) goto discard; if (h == 0 || h > max) h = max; } /* Update elementary stream format (if needed) */ if (w != sys->cur_w || h != sys->cur_h) { if (sys->es != NULL) es_out_Del (demux->out, sys->es); /* Update composite pixmap */ if (sys->window != geo->root) { xcb_free_pixmap (conn, sys->pixmap); /* no-op first time */ xcb_composite_name_window_pixmap (conn, sys->window, sys->pixmap); xcb_create_pixmap (conn, geo->depth, sys->pixmap, geo->root, geo->width, geo->height); } sys->es = InitES (demux, w, h, geo->depth); if (sys->es != NULL) { sys->cur_w = w; sys->cur_h = h; } } /* Capture screen */ xcb_drawable_t drawable = (sys->window != geo->root) ? sys->pixmap : sys->window; free (geo); xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable, x, y, w, h, ~0), NULL); if (img == NULL) return; block_t *block = block_heap_Alloc (img, xcb_get_image_data (img), xcb_get_image_data_length (img)); if (block == NULL) return; /* Send block - zero copy */ if (sys->es != NULL) { if (sys->pts == VLC_TS_INVALID) sys->pts = mdate (); block->i_pts = block->i_dts = sys->pts; es_out_Control (demux->out, ES_OUT_SET_PCR, sys->pts); es_out_Send (demux->out, sys->es, block); sys->pts += sys->interval; } }
HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame) { demux_sys_t *sys = demux_->p_sys; if (videoFrame) { if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) { msg_Warn(demux_, "No input signal detected"); return S_OK; } const int width = videoFrame->GetWidth(); const int height = videoFrame->GetHeight(); const int stride = videoFrame->GetRowBytes(); int bpp = sys->tenbits ? 4 : 2; block_t *video_frame = block_Alloc(width * height * bpp); if (!video_frame) return S_OK; const uint32_t *frame_bytes; videoFrame->GetBytes((void**)&frame_bytes); BMDTimeValue stream_time, frame_duration; videoFrame->GetStreamTime(&stream_time, &frame_duration, CLOCK_FREQ); video_frame->i_flags = BLOCK_FLAG_TYPE_I | sys->dominance_flags; video_frame->i_pts = video_frame->i_dts = VLC_TS_0 + stream_time; if (sys->tenbits) { v210_convert((uint16_t*)video_frame->p_buffer, frame_bytes, width, height); IDeckLinkVideoFrameAncillary *vanc; if (videoFrame->GetAncillaryData(&vanc) == S_OK) { for (int i = 1; i < 21; i++) { uint32_t *buf; if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) != S_OK) break; uint16_t dec[width * 2]; v210_convert(&dec[0], buf, width, 1); block_t *cc = vanc_to_cc(demux_, dec, width * 2); if (!cc) continue; cc->i_pts = cc->i_dts = VLC_TS_0 + stream_time; if (!sys->cc_es) { es_format_t fmt; es_format_Init( &fmt, SPU_ES, VLC_CODEC_EIA608_1 ); fmt.psz_description = strdup(N_("Closed captions 1")); if (fmt.psz_description) { sys->cc_es = es_out_Add(demux_->out, &fmt); msg_Dbg(demux_, "Adding Closed captions stream"); } } if (sys->cc_es) es_out_Send(demux_->out, sys->cc_es, cc); else block_Release(cc); break; // we found the line with Closed Caption data } vanc->Release(); } } else { for (int y = 0; y < height; ++y) { const uint8_t *src = (const uint8_t *)frame_bytes + stride * y; uint8_t *dst = video_frame->p_buffer + width * 2 * y; memcpy(dst, src, width * 2); } } vlc_mutex_lock(&sys->pts_lock); if (video_frame->i_pts > sys->last_pts) sys->last_pts = video_frame->i_pts; vlc_mutex_unlock(&sys->pts_lock); es_out_Control(demux_->out, ES_OUT_SET_PCR, video_frame->i_pts); es_out_Send(demux_->out, sys->video_es, video_frame); } if (audioFrame) { const int bytes = audioFrame->GetSampleFrameCount() * sizeof(int16_t) * sys->channels; block_t *audio_frame = block_Alloc(bytes); if (!audio_frame) return S_OK; void *frame_bytes; audioFrame->GetBytes(&frame_bytes); memcpy(audio_frame->p_buffer, frame_bytes, bytes); BMDTimeValue packet_time; audioFrame->GetPacketTime(&packet_time, CLOCK_FREQ); audio_frame->i_pts = audio_frame->i_dts = VLC_TS_0 + packet_time; vlc_mutex_lock(&sys->pts_lock); if (audio_frame->i_pts > sys->last_pts) sys->last_pts = audio_frame->i_pts; vlc_mutex_unlock(&sys->pts_lock); es_out_Control(demux_->out, ES_OUT_SET_PCR, audio_frame->i_pts); es_out_Send(demux_->out, sys->audio_es, audio_frame); } return S_OK; }