static int Demux( demux_t* p_demux ) { demux_sys_t* p_sys = p_demux->p_sys; /* Last one must be an end time */ while( p_sys->times.i_current + 1 < p_sys->times.i_count && tt_time_Convert( &p_sys->times.p_array[p_sys->times.i_current] ) <= p_sys->i_next_demux_time ) { const vlc_tick_t i_playbacktime = tt_time_Convert( &p_sys->times.p_array[p_sys->times.i_current] ); const vlc_tick_t i_playbackendtime = tt_time_Convert( &p_sys->times.p_array[p_sys->times.i_current + 1] ) - 1; if ( !p_sys->b_slave && p_sys->b_first_time ) { es_out_SetPCR( p_demux->out, VLC_TICK_0 + i_playbacktime ); p_sys->b_first_time = false; } struct vlc_memstream stream; if( vlc_memstream_open( &stream ) ) return VLC_DEMUXER_EGENERIC; tt_node_ToText( &stream, (tt_basenode_t *) p_sys->p_rootnode, &p_sys->times.p_array[p_sys->times.i_current] ); if( vlc_memstream_close( &stream ) == VLC_SUCCESS ) { block_t* p_block = block_heap_Alloc( stream.ptr, stream.length ); if( p_block ) { p_block->i_dts = p_block->i_pts = VLC_TICK_0 + i_playbacktime; p_block->i_length = i_playbackendtime - i_playbacktime; es_out_Send( p_demux->out, p_sys->p_es, p_block ); } } p_sys->times.i_current++; } if ( !p_sys->b_slave ) { es_out_SetPCR( p_demux->out, VLC_TICK_0 + p_sys->i_next_demux_time ); p_sys->i_next_demux_time += VLC_TICK_FROM_MS(125); } if( p_sys->times.i_current + 1 >= p_sys->times.i_count ) return VLC_DEMUXER_EOF; return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * 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; int64_t i_offset = vlc_stream_Tell( p_demux->s ); unsigned i_frames = p_sys->i_block_frames; if( p_sys->i_data_size > 0 && (i_offset - HEADER_LENGTH) >= p_sys->i_data_size ) { return VLC_DEMUXER_EOF; } p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size * i_frames ); if( p_block == NULL ) { msg_Warn( p_demux, "cannot read data" ); return VLC_DEMUXER_EOF; } i_frames = p_block->i_buffer / p_sys->i_frame_size; p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts ); es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, i_frames * FRAME_LENGTH ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * 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; mtime_t i_date; mtime_t i_delta; i_delta = INT64_C(1000000) / CDG_FRAME_RATE; p_block = vlc_stream_Block( p_demux->s, CDG_FRAME_SIZE ); if( p_block == NULL ) { msg_Dbg( p_demux, "cannot read data, eof" ); return 0; } i_date = vlc_stream_Tell( p_demux->s ) / CDG_FRAME_SIZE * i_delta; if( i_date >= date_Get( &p_sys->pts ) + i_delta ) { p_block->i_dts = p_block->i_pts = i_date; date_Set( &p_sys->pts, i_date ); } else { p_block->i_dts = i_date; p_block->i_pts = date_Get( &p_sys->pts ); } es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); return 1; }
static int DemuxOnce (demux_t *demux, bool master) { demux_sys_t *sys = demux->p_sys; mtime_t pts = date_Get (&sys->date); lldiv_t d; unsigned h, m, s, f; d = lldiv (pts, CLOCK_FREQ); f = d.rem * sys->date.i_divider_num / sys->date.i_divider_den / CLOCK_FREQ; d = lldiv (d.quot, 60); s = d.rem; d = lldiv (d.quot, 60); m = d.rem; h = d.quot; char *str; int len = asprintf (&str, "%02u:%02u:%02u:%02u", h, m, s, f); if (len == -1) return -1; block_t *block = block_heap_Alloc (str, len + 1); if (unlikely(block == NULL)) return -1; block->i_buffer = len; assert(str[len] == '\0'); block->i_pts = block->i_dts = pts; block->i_length = date_Increment (&sys->date, 1) - pts; es_out_Send (demux->out, sys->es, block); if (master) es_out_SetPCR(demux->out, pts); 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; vlc_tick_t i_date; p_block = vlc_stream_Block( p_demux->s, CDG_FRAME_SIZE ); if( p_block == NULL ) { msg_Dbg( p_demux, "cannot read data, eof" ); return VLC_DEMUXER_EOF; } i_date = PosToDate( p_demux ); if( i_date >= date_Get( &p_sys->pts ) + CDG_FRAME_DELTA ) { p_block->i_dts = p_block->i_pts = VLC_TICK_0 + i_date; date_Set( &p_sys->pts, VLC_TICK_0 + i_date ); } else { p_block->i_dts = VLC_TICK_0 + i_date; p_block->i_pts = date_Get( &p_sys->pts ); } es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * Demux: *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_frame; const int i_bk = ( p_sys->fmt.audio.i_bitspersample / 8 ) * p_sys->fmt.audio.i_channels; p_frame = block_Alloc( p_sys->fmt.audio.i_rate / 10 * i_bk ); if( !p_frame ) return VLC_DEMUXER_EGENERIC; const int i_read = ModPlug_Read( p_sys->f, p_frame->p_buffer, p_frame->i_buffer ); if( i_read <= 0 ) { /* EOF */ block_Release( p_frame ); return VLC_DEMUXER_EOF; } p_frame->i_buffer = i_read; p_frame->i_dts = p_frame->i_pts = date_Get( &p_sys->pts ); es_out_SetPCR( p_demux->out, p_frame->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_frame ); date_Increment( &p_sys->pts, i_read / i_bk ); return VLC_DEMUXER_SUCCESS; }
static int Demux (demux_t *demux) { demux_sys_t *sys = demux->p_sys; /* Next track */ if (gme_track_ended (sys->emu)) { msg_Dbg (demux, "track %u ended", sys->track_id); if (++sys->track_id >= (unsigned)gme_track_count (sys->emu)) return 0; demux->info.i_update |= INPUT_UPDATE_TITLE; demux->info.i_title = sys->track_id; gme_start_track (sys->emu, sys->track_id); } block_t *block = block_Alloc (2 * 2 * SAMPLES); if (unlikely(block == NULL)) return 0; gme_err_t ret = gme_play (sys->emu, 2 * SAMPLES, (void *)block->p_buffer); if (ret != NULL) { block_Release (block); msg_Err (demux, "%s", ret); return 0; } block->i_pts = block->i_dts = VLC_TS_0 + date_Get (&sys->pts); es_out_SetPCR (demux->out, block->i_pts); es_out_Send (demux->out, sys->es, block); date_Increment (&sys->pts, SAMPLES); return 1; }
static void *DemuxThread( void *p_data ) { demux_t *p_demux = (demux_t *) p_data; demux_sys_t *p_sys = p_demux->p_sys; vlc_tick_t i_next_frame_date = vlc_tick_now() + p_sys->i_frame_interval; int i_status; for(;;) { p_sys->i_cancel_state = vlc_savecancel(); i_status = WaitForMessage( p_sys->p_client, p_sys->i_frame_interval ); vlc_restorecancel( p_sys->i_cancel_state ); /* Ensure we're not building frames too fast */ /* as WaitForMessage takes only a maximum wait */ vlc_tick_wait( i_next_frame_date ); i_next_frame_date += p_sys->i_frame_interval; if ( i_status > 0 ) { p_sys->p_client->frameBuffer = p_sys->p_block->p_buffer; p_sys->i_cancel_state = vlc_savecancel(); i_status = HandleRFBServerMessage( p_sys->p_client ); vlc_restorecancel( p_sys->i_cancel_state ); if ( ! i_status ) { msg_Warn( p_demux, "Cannot get announced data. Server closed ?" ); es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; return NULL; } else { block_t *p_block = block_Duplicate( p_sys->p_block ); if ( p_block ) /* drop frame/content if no next block */ { p_sys->p_block->i_dts = p_sys->p_block->i_pts = vlc_tick_now(); es_out_SetPCR( p_demux->out, p_sys->p_block->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_sys->p_block ); p_sys->p_block = p_block; } } } } return NULL; }
/***************************************************************************** * 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; p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size ); if( p_block == NULL ) return VLC_DEMUXER_EOF; p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts ); es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, p_sys->i_frame_samples ); return VLC_DEMUXER_SUCCESS; }
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 = vlc_tick_now(); es_out_SetPCR(demux->out, 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; /* set PCR */ es_out_SetPCR( p_demux->out, VLC_TS_0 + p_sys->i_time ); p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size ); if( p_block == 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; }
/** * 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; } unsigned w = sys->w; unsigned 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 < (int)(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 < (int)(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 > (unsigned)max) w = max; y = sys->y; max = (int)geo->height - y; if (max <= 0) goto discard; if (h == 0 || h > (unsigned)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: %s", vlc_strerror_c(errno)); 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: %s", vlc_strerror_c(errno)); 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_SetPCR(demux->out, block->i_pts); es_out_Send (demux->out, sys->es, block); } else block_Release (block); }
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) { block_Release (block); if (frames == -EAGAIN) continue; val = snd_pcm_recover (pcm, frames, 1); if (val == 0) { msg_Warn (demux, "cannot read samples: %s", snd_strerror (frames)); snd_pcm_state_t state = snd_pcm_state (pcm); switch (state) { case SND_PCM_STATE_PREPARED: val = snd_pcm_start (pcm); if (val < 0) { msg_Err (demux, "cannot prepare device: %s", snd_strerror (val)); return NULL; } continue; case SND_PCM_STATE_RUNNING: continue; default: break; } } 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_SetPCR(demux->out, block->i_pts); es_out_Send (demux->out, sys->es, block); } return NULL; }
/***************************************************************************** * Demux: *****************************************************************************/ static void *DemuxThread( void *p_data ) { demux_t *p_demux = (demux_t *) p_data; demux_sys_t *p_sys = p_demux->p_sys; p_sys->i_starttime = vlc_tick_now(); vlc_tick_t i_next_frame_date = vlc_tick_now() + p_sys->i_frame_interval; int i_ret; for(;;) { i_ret = 0; p_sys->i_cancel_state = vlc_savecancel(); if ( freerdp_shall_disconnect( p_sys->p_instance ) ) { vlc_restorecancel( p_sys->i_cancel_state ); msg_Warn( p_demux, "RDP server closed session" ); es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; return NULL; } struct { void* pp_rfds[RDP_MAX_FD]; /* Declared by rdp */ void* pp_wfds[RDP_MAX_FD]; int i_nbr; int i_nbw; struct pollfd ufds[RDP_MAX_FD]; } fds; fds.i_nbr = fds.i_nbw = 0; if ( freerdp_get_fds( p_sys->p_instance, fds.pp_rfds, &fds.i_nbr, fds.pp_wfds, &fds.i_nbw ) != true ) { vlc_restorecancel( p_sys->i_cancel_state ); msg_Err( p_demux, "cannot get FDS" ); } else if ( (fds.i_nbr + fds.i_nbw) > 0 && p_sys->es ) { vlc_restorecancel( p_sys->i_cancel_state ); int i_count = 0; for( int i = 0; i < fds.i_nbr; i++ ) { fds.ufds[ i_count ].fd = (long) fds.pp_rfds[ i ]; fds.ufds[ i_count ].events = POLLIN ; fds.ufds[ i_count++ ].revents = 0; } for( int i = 0; i < fds.i_nbw && i_count < RDP_MAX_FD; i++ ) { /* may be useless */ fds.ufds[ i_count ].fd = (long) fds.pp_wfds[ i ]; fds.ufds[ i_count ].events = POLLOUT; fds.ufds[ i_count++ ].revents = 0; } i_ret = poll( fds.ufds, i_count, p_sys->i_frame_interval * 1000/2 ); } else { vlc_restorecancel( p_sys->i_cancel_state ); } vlc_tick_wait( i_next_frame_date ); i_next_frame_date += p_sys->i_frame_interval; if ( i_ret >= 0 ) { /* Do the rendering */ p_sys->i_cancel_state = vlc_savecancel(); freerdp_check_fds( p_sys->p_instance ); vlc_restorecancel( p_sys->i_cancel_state ); block_t *p_block = block_Duplicate( p_sys->p_block ); if (likely( p_block && p_sys->p_block )) { p_sys->p_block->i_dts = p_sys->p_block->i_pts = vlc_tick_now() - p_sys->i_starttime; es_out_SetPCR( p_demux->out, p_sys->p_block->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_sys->p_block ); p_sys->p_block = p_block; } } } return NULL; }
/***************************************************************************** * Demux: *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; int i_ret, i_mux_rate; block_t *p_pkt; i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack ); if( i_ret < 0 ) { return VLC_DEMUXER_EOF; } else if( i_ret == 0 ) { if( !p_sys->b_lost_sync ) { msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...", vlc_stream_Tell(p_demux->s) ); NotifyDiscontinuity( p_sys->tk, p_demux->out ); } p_sys->b_lost_sync = true; return VLC_DEMUXER_SUCCESS; } if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" ); p_sys->b_lost_sync = false; if( p_sys->i_length == VLC_TICK_INVALID && p_sys->b_seekable ) { if( !FindLength( p_demux ) ) return VLC_DEMUXER_EGENERIC; } if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL ) { return VLC_DEMUXER_EOF; } if( p_pkt->i_buffer < 4 ) { block_Release( p_pkt ); return VLC_DEMUXER_EGENERIC; } const uint8_t i_stream_id = p_pkt->p_buffer[3]; switch( i_stream_id ) { case PS_STREAM_ID_END_STREAM: block_Release( p_pkt ); break; case PS_STREAM_ID_PACK_HEADER: if( !ps_pkt_parse_pack( p_pkt, &p_sys->i_pack_scr, &i_mux_rate ) ) { if( p_sys->i_first_scr == VLC_TICK_INVALID ) p_sys->i_first_scr = p_sys->i_pack_scr; CheckPCR( p_sys, p_demux->out, p_sys->i_pack_scr ); p_sys->i_scr = p_sys->i_pack_scr; p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s ); if( !p_sys->b_have_pack ) p_sys->b_have_pack = true; /* done later on to work around bad vcd/svcd streams */ /* es_out_SetPCR( p_demux->out, p_sys->i_scr ); */ if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate; } block_Release( p_pkt ); break; case PS_STREAM_ID_SYSTEM_HEADER: if( !ps_pkt_parse_system( p_pkt, &p_sys->psm, p_sys->tk ) ) { int i; for( i = 0; i < PS_TK_COUNT; i++ ) { ps_track_t *tk = &p_sys->tk[i]; if( !tk->b_configured && tk->fmt.i_cat != UNKNOWN_ES ) { if( tk->b_seen ) tk->es = es_out_Add( p_demux->out, &tk->fmt ); /* else create when seeing packet */ tk->b_configured = true; } } } block_Release( p_pkt ); break; case PS_STREAM_ID_MAP: if( p_sys->psm.i_version == 0xFFFF ) msg_Dbg( p_demux, "contains a PSM"); ps_psm_fill( &p_sys->psm, p_pkt, p_sys->tk, p_demux->out ); block_Release( p_pkt ); break; default: /* Reject non video/audio nor PES */ if( i_stream_id < 0xC0 || i_stream_id > 0xEF ) { block_Release( p_pkt ); break; } /* fallthrough */ case PS_STREAM_ID_PRIVATE_STREAM1: case PS_STREAM_ID_EXTENDED: { int i_id = ps_pkt_id( p_pkt ); /* Small heuristic to improve MLP detection from AOB */ if( i_id == 0xa001 && p_sys->i_aob_mlp_count < 500 ) { p_sys->i_aob_mlp_count++; } else if( i_id == 0xbda1 && p_sys->i_aob_mlp_count > 0 ) { p_sys->i_aob_mlp_count--; i_id = 0xa001; } bool b_new = false; ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)]; if( !tk->b_configured ) { if( !ps_track_fill( tk, &p_sys->psm, i_id, p_pkt, false ) ) { /* No PSM and no probing yet */ if( p_sys->format == PSMF_PS ) { if( tk->fmt.i_cat == VIDEO_ES ) tk->fmt.i_codec = VLC_CODEC_H264; #if 0 if( i_stream_id == PS_STREAM_ID_PRIVATE_STREAM1 ) { es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_ATRAC3P ); tk->fmt.audio.i_blockalign = 376; tk->fmt.audio.i_channels = 2; tk->fmt.audio.i_rate = 44100; } #endif } tk->es = es_out_Add( p_demux->out, &tk->fmt ); b_new = true; tk->b_configured = true; } else { msg_Dbg( p_demux, "es id=0x%x format unknown", i_id ); } } /* Late creation from system header */ if( !tk->b_seen && tk->b_configured && !tk->es && tk->fmt.i_cat != UNKNOWN_ES ) tk->es = es_out_Add( p_demux->out, &tk->fmt ); tk->b_seen = true; /* The popular VCD/SVCD subtitling WinSubMux does not * renumber the SCRs when merging subtitles into the PES */ if( tk->b_seen && !p_sys->b_bad_scr && ( tk->fmt.i_codec == VLC_CODEC_OGT || tk->fmt.i_codec == VLC_CODEC_CVD ) ) { p_sys->b_bad_scr = true; p_sys->i_first_scr = VLC_TICK_INVALID; } if( p_sys->i_pack_scr != VLC_TICK_INVALID && !p_sys->b_bad_scr ) { if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) && tk->i_first_pts != VLC_TICK_INVALID && tk->i_first_pts - p_sys->i_pack_scr > VLC_TICK_FROM_SEC(2)) { msg_Warn( p_demux, "Incorrect SCR timing offset by of %"PRId64 "ms, disabling", MS_FROM_VLC_TICK(tk->i_first_pts - p_sys->i_pack_scr) ); p_sys->b_bad_scr = true; /* Disable Offset SCR */ p_sys->i_first_scr = VLC_TICK_INVALID; } else es_out_SetPCR( p_demux->out, p_sys->i_pack_scr ); } if( tk->b_configured && tk->es && !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) ) { if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES ) { if( !p_sys->b_bad_scr && p_sys->i_pack_scr != VLC_TICK_INVALID && p_pkt->i_pts != VLC_TICK_INVALID && p_sys->i_pack_scr > p_pkt->i_pts + VLC_TICK_FROM_MS(250) ) { msg_Warn( p_demux, "Incorrect SCR timing in advance of %" PRId64 "ms, disabling", MS_FROM_VLC_TICK(p_sys->i_pack_scr - p_pkt->i_pts) ); p_sys->b_bad_scr = true; p_sys->i_first_scr = VLC_TICK_INVALID; } if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id ) { p_sys->i_scr_track_id = tk->i_id; } } if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) && p_sys->i_scr_track_id == tk->i_id && p_pkt->i_pts != VLC_TICK_INVALID ) { /* A hack to sync the A/V on PES files. */ msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts ); CheckPCR( p_sys, p_demux->out, p_pkt->i_pts ); p_sys->i_scr = p_pkt->i_pts; if( p_sys->i_first_scr == VLC_TICK_INVALID ) p_sys->i_first_scr = p_sys->i_scr; es_out_SetPCR( p_demux->out, p_pkt->i_pts ); } if( tk->fmt.i_codec == VLC_CODEC_TELETEXT && p_pkt->i_pts == VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID ) { /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A) * In this case use the last SCR + 40ms */ p_pkt->i_pts = p_sys->i_scr + VLC_TICK_FROM_MS(40); } if( p_pkt->i_pts > p_sys->i_current_pts ) { p_sys->i_current_pts = p_pkt->i_pts; } if( tk->i_next_block_flags ) { p_pkt->i_flags = tk->i_next_block_flags; tk->i_next_block_flags = 0; } #if 0 if( tk->fmt.i_codec == VLC_CODEC_ATRAC3P ) { p_pkt->p_buffer += 14; p_pkt->i_buffer -= 14; } #endif es_out_Send( p_demux->out, tk->es, p_pkt ); } else { block_Release( p_pkt ); } p_sys->i_pack_scr = VLC_TICK_INVALID; } break; } demux_UpdateTitleFromStream( p_demux ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * Demux: *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; AVPacket pkt; block_t *p_frame; vlc_tick_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 || (unsigned) pkt.stream_index >= p_sys->i_tracks ) { av_packet_unref( &pkt ); return 1; } struct avformat_track_s *p_track = &p_sys->tracks[pkt.stream_index]; 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_stream->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE ) { if( ( p_frame = block_Alloc( pkt.size + 3 ) ) == NULL ) { av_packet_unref( &pkt ); return 0; } p_frame->p_buffer[0] = 0x20; p_frame->p_buffer[1] = 0x00; memcpy( &p_frame->p_buffer[2], pkt.data, pkt.size ); p_frame->p_buffer[p_frame->i_buffer - 1] = 0x3f; } 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 */ if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) { i_start_time = vlc_tick_from_frac(p_sys->ic->start_time, AV_TIME_BASE); } else i_start_time = 0; if( pkt.dts == (int64_t)AV_NOPTS_VALUE ) p_frame->i_dts = VLC_TICK_INVALID; else { p_frame->i_dts = vlc_tick_from_frac( pkt.dts * p_stream->time_base.num, p_stream->time_base.den ) - i_start_time + VLC_TICK_0; } if( pkt.pts == (int64_t)AV_NOPTS_VALUE ) p_frame->i_pts = VLC_TICK_INVALID; else { p_frame->i_pts = vlc_tick_from_frac( pkt.pts * p_stream->time_base.num, p_stream->time_base.den ) - i_start_time + VLC_TICK_0; } if( pkt.duration > 0 && p_frame->i_length <= 0 ) p_frame->i_length = vlc_tick_from_samples(pkt.duration * 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_TICK_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_track->i_pcr != VLC_TICK_INVALID && p_track->i_pcr + p_frame->i_length > p_frame->i_dts ) { p_frame->i_dts = p_frame->i_pts = p_track->i_pcr + 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_TICK_INVALID && p_track->p_es != NULL ) p_track->i_pcr = p_frame->i_dts; vlc_tick_t i_ts_max = INT64_MIN; for( unsigned i = 0; i < p_sys->i_tracks; i++ ) { if( p_sys->tracks[i].p_es != NULL ) i_ts_max = __MAX( i_ts_max, p_sys->tracks[i].i_pcr ); } vlc_tick_t i_ts_min = INT64_MAX; for( unsigned i = 0; i < p_sys->i_tracks; i++ ) { if( p_sys->tracks[i].p_es != NULL && p_sys->tracks[i].i_pcr != VLC_TICK_INVALID && p_sys->tracks[i].i_pcr + VLC_TICK_FROM_SEC(10)>= i_ts_max ) i_ts_min = __MIN( i_ts_min, p_sys->tracks[i].i_pcr ); } if( i_ts_min >= p_sys->i_pcr && likely(i_ts_min != INT64_MAX) ) { p_sys->i_pcr = i_ts_min; es_out_SetPCR( p_demux->out, p_sys->i_pcr ); UpdateSeekPoint( p_demux, p_sys->i_pcr ); } if( p_track->p_es != NULL ) es_out_Send( p_demux->out, p_track->p_es, p_frame ); else block_Release( p_frame ); av_packet_unref( &pkt ); 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; p_block_in = vlc_stream_Block( p_demux->s, H26X_PACKET_SIZE ); if( p_block_in == NULL ) { b_eof = true; } else { p_block_in->i_dts = date_Get( &p_sys->dts ); } 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_block_in ) { p_block_in->i_dts = date_Get( &p_sys->dts ); p_block_in->i_pts = VLC_TICK_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 ) { block_ChainRelease( p_block_out ); 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; const vlc_tick_t i_frame_dts = p_block_out->i_dts; const vlc_tick_t i_frame_length = p_block_out->i_length; 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->p_packetizer->fmt_out.video.i_frame_rate ) { 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, 2 * p_sys->frame_rate_num, p_sys->frame_rate_den ); date_Set( &p_sys->dts, VLC_TICK_0 ); msg_Dbg( p_demux, "using %.2f fps", (double) p_sys->frame_rate_num / p_sys->frame_rate_den ); } es_out_SetPCR( p_demux->out, date_Get( &p_sys->dts ) ); unsigned i_nb_fields; if( i_frame_length > 0 ) { i_nb_fields = round( (double)i_frame_length * 2 * p_sys->frame_rate_num / ( p_sys->frame_rate_den * CLOCK_FREQ ) ); } else i_nb_fields = 2; if( i_nb_fields <= 6 ) /* in the legit range */ date_Increment( &p_sys->dts, i_nb_fields ); else /* Somehow some discontinuity */ date_Set( &p_sys->dts, i_frame_dts ); } p_block_out = p_next; } } return (b_eof) ? VLC_DEMUXER_EOF : VLC_DEMUXER_SUCCESS; }