static int Del( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; if( !p_sys->p_out ) OutputStart( p_stream ); if( id->p_first ) block_ChainRelease( id->p_first ); assert( !id->id || p_sys->p_out ); if( id->id ) sout_StreamIdDel( p_sys->p_out, id->id ); es_format_Clean( &id->fmt ); TAB_REMOVE( p_sys->i_id, p_sys->id, id ); if( p_sys->i_id <= 0 ) { if( !p_sys->p_out ) p_sys->b_drop = false; } free( id ); return VLC_SUCCESS; }
static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ) { sout_stream_sys_t *p_sys = p_stream->p_sys; if( p_sys->i_date_start < 0 ) p_sys->i_date_start = mdate(); if( !p_sys->p_out && ( mdate() - p_sys->i_date_start > p_sys->i_max_wait || p_sys->i_size > p_sys->i_max_size ) ) { msg_Dbg( p_stream, "Starting recording, waited %ds and %dbyte", (int)((mdate() - p_sys->i_date_start)/1000000), (int)p_sys->i_size ); OutputStart( p_stream ); } OutputSend( p_stream, id, p_buffer ); return VLC_SUCCESS; }
static void * avLoop( void * arg ) { int loc_frames = 0; int loc_bytes; int loc_quit = 1; NMS_SRV_STATUS_t loc_preState = NMS_STATUS_PLAYER_STOPPED; int loc_cur_t = 0; int loc_next_t = 0; int loc_prev_t = 0; int loc_first_time = 0; int loc_preload; int loc_ffrw_scan_step = 0; media_buf_t loc_buf; long loc_info_duration; LOCK_PLAYMUTEX(); if(editmode) { playState = NMS_STATUS_PLAYER_VF; loc_preload = 1; frameByFrame = 1; } else { playState =NMS_STATUS_PLAYER_PLAY; loc_preload = PRELOAD_FRAMES; frameByFrame = 0; } UNLOCK_PLAYMUTEX(); do { DBGMSG("In avloop now."); /* preload */ while (loc_frames < loc_preload) { if (1 == OutputGetBuffer(&loc_buf, 0, 1)) { WPRINT("GetBuffer failed."); break; } loc_bytes = InputGetData(&loc_buf); if (loc_bytes == 0) continue; if (loc_bytes <0 ) { // hit EOF, set flag to flush. loc_quit = 0; LOCK_PLAYMUTEX(); playing = 0; UNLOCK_PLAYMUTEX(); break; } //DBGMSG("input data returned. "); LOCK_PLAYMUTEX(); playtime = OutputGetPlaytime(); UNLOCK_PLAYMUTEX(); #ifdef LOG_TIME_STAMP__ if (loc_buf.curbuf == &loc_buf.abuf) DBGLOG(" aT = %d\n", loc_buf.curbuf->tsms); else DBGLOG("---vT = %d\n", loc_buf.curbuf->tsms); #endif OutputWrite(&loc_buf); if (loc_buf.curbuf == &loc_buf.abuf) loc_frames++; } DBGMSG("preload finished."); OutputStart(); /* start output */ DBGMSG("output started."); } while(0); LOCK_PLAYMUTEX(); preloaded = 1; everPlayed = 1; UNLOCK_PLAYMUTEX(); main_play_loop: // preloaded... while (1) { int loc_playState; int loc_iSeekFlag; int loc_iBookMark; int loc_sfrwLevelFinal; LOCK_PLAYMUTEX(); if (!playing) { UNLOCK_PLAYMUTEX(); break; } loc_playState = playState; UNLOCK_PLAYMUTEX(); switch (loc_playState) { case NMS_STATUS_PLAYER_PAUSE: if (loc_preState != NMS_STATUS_PLAYER_PAUSE) { OutputPause(1); LOCK_PLAYMUTEX(); playedOrPaused = NMS_STATUS_PLAYER_PAUSE; UNLOCK_PLAYMUTEX(); loc_preState = NMS_STATUS_PLAYER_PAUSE; } continue; case NMS_STATUS_PLAYER_PLAY: { LOCK_PLAYMUTEX(); loc_iSeekFlag = iSeekFlag; loc_iBookMark = iBookMark; UNLOCK_PLAYMUTEX(); if (loc_preState != NMS_STATUS_PLAYER_PLAY || loc_iSeekFlag) { LOCK_PLAYMUTEX(); playedOrPaused = NMS_STATUS_PLAYER_PLAY; loc_info_duration = info.duration; UNLOCK_PLAYMUTEX(); if (loc_preState == NMS_STATUS_PLAYER_PAUSE) { OutputPause(0); LOCK_PLAYMUTEX(); muted = 0; UNLOCK_PLAYMUTEX(); } else if (loc_iSeekFlag) { if (loc_info_duration - loc_iBookMark > 100) { loc_next_t = InputSeek(loc_iBookMark); OutputFlush(loc_next_t); } LOCK_PLAYMUTEX(); iSeekFlag = 0; UNLOCK_PLAYMUTEX(); } else { LOCK_PLAYMUTEX(); if (muted) { muted = 0; OutputMute(muted); } loc_sfrwLevelFinal = sfrwLevelFinal; UNLOCK_PLAYMUTEX(); if (loc_preState == NMS_STATUS_PLAYER_SF) { int loc_cur_tmp; LOCK_PLAYMUTEX(); loc_cur_tmp = playtime; UNLOCK_PLAYMUTEX(); loc_next_t = loc_first_time + (loc_cur_tmp - loc_first_time) / loc_sfrwLevelFinal; loc_next_t = InputSeek(loc_next_t); OutputFlush(loc_next_t); } } loc_preState = NMS_STATUS_PLAYER_PLAY; loc_prev_t = 0; } } break; case NMS_STATUS_PLAYER_FF: case NMS_STATUS_PLAYER_RW: if (loc_preState != loc_playState) { LOCK_PLAYMUTEX(); loc_cur_t = playtime; UNLOCK_PLAYMUTEX(); OutputFlush(loc_cur_t); if (loc_preState == NMS_STATUS_PLAYER_PAUSE) OutputPause(0); LOCK_PLAYMUTEX(); if (!muted) { muted = 1; OutputMute(muted); } loc_cur_t = playtime; loc_first_time = loc_cur_t; loc_next_t = loc_cur_t; loc_prev_t = loc_cur_t; loc_preState = playState; UNLOCK_PLAYMUTEX(); } LOCK_PLAYMUTEX(); if (ffrwLevel == 0) { UNLOCK_PLAYMUTEX(); continue; } else if (ffrwLevel > 2) loc_ffrw_scan_step = SCAN_STEP2_MS; else loc_ffrw_scan_step = SCAN_STEP1_MS; get_new_timestamp: if (loc_preState == NMS_STATUS_PLAYER_FF) { loc_info_duration = info.duration; if (loc_info_duration != 0 && (playtime + ffrwLevel * loc_ffrw_scan_step) >= loc_info_duration) { loc_next_t = loc_info_duration; loc_next_t = InputSeek(loc_next_t); OutputFlush(loc_next_t); if(editmode) { playState = NMS_STATUS_PLAYER_PLAY; UNLOCK_PLAYMUTEX(); break; } else { loc_quit = 0; UNLOCK_PLAYMUTEX(); goto bail; } } else { playtime += ffrwLevel * loc_ffrw_scan_step; loc_next_t = playtime; if (rptState == NMS_PLAYBACK_REPEAT_ON) { if (loc_next_t >= rptB) { loc_next_t = rptB; loc_next_t = InputSeek(loc_next_t); OutputFlush(loc_next_t); UNLOCK_PLAYMUTEX(); continue; } } } } else { if (playtime +ffrwLevel * loc_ffrw_scan_step <= 0) { loc_next_t = 0; loc_next_t = InputSeek(loc_next_t); OutputFlush(loc_next_t); if(editmode) { playState = NMS_STATUS_PLAYER_VF; frameByFrame = 1; loc_preState = NMS_STATUS_PLAYER_PLAY; UNLOCK_PLAYMUTEX(); break; } else playState = NMS_STATUS_PLAYER_PLAY; ffrwLevel = 0; UNLOCK_PLAYMUTEX(); continue; } else { playtime += ffrwLevel * loc_ffrw_scan_step; loc_next_t = playtime; if (rptState == NMS_PLAYBACK_REPEAT_ON) { if (loc_next_t <= rptA) { loc_next_t = rptA; loc_next_t = InputSeek(loc_next_t); OutputFlush(loc_next_t); UNLOCK_PLAYMUTEX(); continue; } } } } loc_next_t = InputSeek(loc_next_t); OutputFlush(loc_next_t); if ((loc_preState == NMS_STATUS_PLAYER_FF && loc_prev_t >= loc_next_t) || (loc_preState == NMS_STATUS_PLAYER_RW && loc_prev_t <= loc_next_t)) { goto get_new_timestamp; } loc_prev_t = loc_cur_t; loc_cur_t = loc_next_t; UNLOCK_PLAYMUTEX(); break; case NMS_STATUS_PLAYER_VF: LOCK_PLAYMUTEX(); DBGLOG("!!!!!!!!!!!!!!!play VF,mute=%d\n",muted); if (frameByFrame == 1) { OutputPause(0); loc_cur_t = playtime; OutputFlush(loc_cur_t); if (!muted) { muted = 1; OutputMute(muted); } } playState = NMS_STATUS_PLAYER_PAUSE; loc_cur_t = playtime; UNLOCK_PLAYMUTEX(); loc_next_t = loc_cur_t; loc_prev_t = loc_cur_t; loc_first_time = loc_cur_t; break; case NMS_STATUS_PLAYER_SF: if (loc_preState != NMS_STATUS_PLAYER_SF) { LOCK_PLAYMUTEX(); loc_cur_t = playtime; OutputFlush(loc_cur_t); if (loc_preState == NMS_STATUS_PLAYER_PAUSE) OutputPause(0); if (!muted) { muted = 1; OutputMute(muted); } loc_cur_t = playtime; UNLOCK_PLAYMUTEX(); loc_next_t = loc_cur_t; loc_prev_t = loc_cur_t; loc_preState = NMS_STATUS_PLAYER_SF; } break; case NMS_STATUS_PLAYER_STOPPED: if (loc_preState == NMS_STATUS_PLAYER_PAUSE) OutputPause(0); loc_preState = NMS_STATUS_PLAYER_STOPPED; loc_quit = 1; goto bail; default: LOCK_PLAYMUTEX(); playState = loc_preState; UNLOCK_PLAYMUTEX(); break; } LOCK_PLAYMUTEX(); if (rptState == NMS_PLAYBACK_REPEAT_ON) { loc_cur_t = playtime; if (loc_cur_t > rptB) { loc_cur_t = InputSeek(rptA); OutputFlush(loc_cur_t); } } UNLOCK_PLAYMUTEX(); if ( 1 == OutputGetBuffer(&loc_buf, 1000, 0)) { //DBGMSG("buffer full or playback paused!"); continue; } loc_bytes = InputGetData(&loc_buf); if (loc_bytes == 0) { WPRINT("zero bytes returned!"); continue; } LOCK_PLAYMUTEX(); if (loc_bytes < 0) { if(editmode) { UNLOCK_PLAYMUTEX(); continue; } else { WPRINT("EOF reached!"); // hit EOF, set flag to flush. loc_quit = 0; UNLOCK_PLAYMUTEX(); break; } } UNLOCK_PLAYMUTEX(); #ifdef LOG_TIME_STAMP__ if (loc_buf.curbuf == &loc_buf.abuf) DBGLOG(" aT = %d\n", loc_buf.curbuf->tsms); else DBGLOG("---vT = %d\n", loc_buf.curbuf->tsms); #endif LOCK_PLAYMUTEX(); playtime = OutputGetPlaytime(); if (loc_buf.curbuf == &loc_buf.abuf) { if (loc_preState != NMS_STATUS_PLAYER_PLAY && rptState != NMS_PLAYBACK_REPEAT_ON) { UNLOCK_PLAYMUTEX(); continue; } } UNLOCK_PLAYMUTEX(); if (loc_preState != NMS_STATUS_PLAYER_PLAY && loc_preState != NMS_STATUS_PLAYER_PAUSE) { if (loc_first_time == 0) { loc_first_time = loc_cur_t; } if (loc_preState == NMS_STATUS_PLAYER_SF) { loc_buf.vbuf.tsms = loc_buf.vbuf.tsms - loc_first_time; LOCK_PLAYMUTEX(); loc_buf.vbuf.tsms *= sfrwLevel; UNLOCK_PLAYMUTEX(); loc_buf.vbuf.tsms += loc_first_time; } loc_prev_t = loc_cur_t; } OutputWrite(&loc_buf); } DBGMSG("Exit main playback loop.\n"); // if quit, re-fetch the lock here bail: LOCK_PLAYMUTEX(); ffrwLevel = 0; sfrwLevel = 0; UNLOCK_PLAYMUTEX(); if (loc_preState == NMS_STATUS_PLAYER_PAUSE) { OutputPause(0); } LOCK_PLAYMUTEX(); if (muted) { muted = 0; OutputMute(muted); } UNLOCK_PLAYMUTEX(); // We used to call InputFinish here, but let's wait a while, because we may be asked to seek again later, // while draining the output buffer. And we'll need input to be active if we want to have something to seek into. if (loc_quit) { LOCK_PLAYMUTEX(); InputFinish(); // If we're quitting the server, we really don't want to wait that video output is drained. // We flush it down the toilet without sending it to the TV. OutputFinish(0); UNLOCK_PLAYMUTEX(); } else { unsigned long remain; // We're at the EOF of a playback. We may have some data left in the dm320 // gargantuan output buffers, and we need to properly make sure it goes all to TV before we're done. // // We can't really call a blocking flush here (like OutputFinish(1)). // This is because the server will freeze otherwise and be unable to process // commands (like STOP or PAUSE) that come in during the final draining of the output buffer. // // This is an improvement over the old way of just waiting some time before calling the // blocking flush: it instead keeps checking the amount of data in the dm320 video output buffer // and doesn't call the blocking flush until it's all drained. It sleeps a small amount of time // between checks, then before the next check it processes commands. // // HACK: // It works better than before, however it's still a bit of an hack, since this // polling is really not elegant at all. It is much better to setup a callback and // have imedia call us when there's no more data in the output buffer. // Or something like that. --nero LOCK_PLAYMUTEX(); playing = 1; //Restore the playback flag, since we're still actually playing. UNLOCK_PLAYMUTEX(); remain = OutputGetBufferedSize(); WPRINT("Entering buffer drain loop (remain %lu bytes).\n", remain); while (remain > 0) { LOCK_PLAYMUTEX(); if (!playing) { UNLOCK_PLAYMUTEX(); break; } DBGMSG("Draining output buffer. Bytes remaining: %lu\n", remain); if (playState == NMS_STATUS_PLAYER_PAUSE) OutputPause(1); else { OutputPause(0); // If we're asked to seek (ffw, rew or point-seek), let's just return in the main loop. // The logic in the loop will take care of everything else, we don't need to do anything more here. if (playState == NMS_STATUS_PLAYER_FF || playState == NMS_STATUS_PLAYER_RW || (playState == NMS_STATUS_PLAYER_PLAY && iSeekFlag != 0)) { DBGMSG("Going back to main playback loop.\n"); UNLOCK_PLAYMUTEX(); goto main_play_loop; } } UNLOCK_PLAYMUTEX(); usleep(DRAIN_POLL_TICK); remain = OutputGetBufferedSize(); } DBGMSG("Exited drain loop. Playing: %d - Remain: %lu\n", playing, remain); LOCK_PLAYMUTEX(); InputFinish(); OutputPause(0); //before finish output must make sure pause flag is cleared //Let's always call a final non-blocking flush. Thus if there are bugs in the above logic, //we notice a clip at end of video (due to flushing to kingdom come the last part of data), //and hopefully we come here to look ;) --nero OutputFinish(0); UNLOCK_PLAYMUTEX(); } // clear playing and ffrw flag, and release lock before // joining ffrw thread. LOCK_PLAYMUTEX(); playing = 0; rptState = NMS_PLAYBACK_REPEAT_OFF; if (playtype == NPT_FILE) playState = NMS_STATUS_PLAYER_STOPPED; else playState = NMS_STATUS_PLAYER_NEXT; DBGMSG("input output finished."); // check to play next file. if ((0 == loc_quit) && (playtype != NPT_FILE)) { DBGMSG("searching for next file."); //if repeat is single and the file is not played, stop nextfile loop if (!((repeat == RM_REPEAT) && (errorStatus == NMS_STATUS_NOT_PLAYABLE))) trackChange = TC_NORMAL; UNLOCK_PLAYMUTEX(); pthread_cond_broadcast(&nextFileCond); } else UNLOCK_PLAYMUTEX(); pthread_exit(NULL); }