📄 xaosproducer.cpp
字号:
if (/*ts_running*/1) { bigtime_t now_real = BTimeSource::RealTime(); if (m_stopping) { // There's a pending Stop request. if (now_real >= TimeSource()->RealTimeFor(m_tpStop, TotalLatency())) { // It's time to handle that Stop request. TRANSPORT(stderr, "XaoSProducer::Stop() takes effect\n"); m_running = false; m_stopping = false; // we've now stopped if (m_seeking) { // There's a seek pending, but we'll defer any // pending seeks until we next start. m_seeking = false; } else { // Set the seek time so that, by default, we // restart where we stopped. m_tmSeekTo = m_tpStop-m_delta; TRANSPORT(stderr, "Setting m_tmSeekTo to %.4f\n", us_to_s(m_tmSeekTo)); } // Very important! Tell the Consumer that we're no longer // sending data to it, so it doesn't sit around waiting for // the buffers that never come. if (connected) { SendDataStatus(B_DATA_NOT_AVAILABLE, m_output.destination, m_tpStop); } // Restart the loop because we changed timing info. continue; } else { // It's not quite yet time to Stop, but if it's a sooner // event than our next perf_target, set it to be the // next perf_target. if (m_tpStop < perf_target) { TRANSPORT(stderr, "m_tpStop perf_target from %.4f to %.4f\n", us_to_s(perf_target), us_to_s(m_tpStop)); perf_target = m_tpStop; } } } if (m_seeking) { // There's a pending Seek request. if (now_real >= TimeSource()->RealTimeFor(m_tpSeekAt, TotalLatency())) { // It's time to handle that Seek request. TRANSPORT(stderr, "XaoSProducer::Seek() takes effect\n"); m_seeking = false; // Seek gives us the relationship between media time // and performance time. We represent this relationship // via m_delta -- see the description in XaoSProducer.h. // // Note: m_frames_played is not addressed here, which I // believe is incorrect. Something to look into when // we actually use Seek... m_delta = m_tpSeekAt-m_tmSeekTo; TRANSPORT(stderr, "setting m_delta to %.4f\n", us_to_s(m_delta)); // Restart the loop because we changed timing info. continue; } else { // It's not quite yet time to Seek, but if it's a sooner // event than our next perf_target, set it to be the // next perf_target. if (m_tpSeekAt < perf_target) { TRANSPORT(stderr, "m_tpSeek perf_target from %.4f to %.4f\n", us_to_s(perf_target), us_to_s(m_tpSeekAt)); perf_target = m_tpSeekAt; } } } if (m_starting) { // There's a pending Start request. printf("Starting thread!\n"); if (now_real >= TimeSource()->RealTimeFor(m_tpStart, TotalLatency())) { printf("Starting OK\n"); // It's time to handle that Start request. TRANSPORT(stderr, "XaoSProducer::Start() takes effect\n"); m_running = true; // Seek to the correct point in the media before // we begin. This offset might have been set by // a Seek operation or the last Stop operation. // We seek by setting the offset between media time // and performance time. m_delta = m_tpStart-m_tmSeekTo; TRANSPORT(stderr, "setting m_delta to %.4f\n", us_to_s(m_delta)); m_frames_played = 0; m_starting = false; // we've now started // Very important! Tell the Consumer that we'll be sending // data to it, so it's expecting us. if (connected) { SendDataStatus(B_DATA_AVAILABLE, m_output.destination, m_tpStart); } // Restart the loop because we changed timing info. continue; } else { // It's not quite yet time to Start, but if it's a sooner // event than our next perf_target, set it to be the // next perf_target. if (m_tpStart < perf_target) { TRANSPORT(stderr, "m_tpStart perf_target from %.4f to %.4f\n", us_to_s(perf_target), us_to_s(m_tpStart)); perf_target = m_tpStart; } } } // Finally, calculate the all-important timeout value. // The timeout value is the difference in real time // between now and the real time at which our thread // needs to handle the next event which occurs at // perf_target. timeout = TimeSource()->RealTimeFor(perf_target, TotalLatency()) - BTimeSource::RealTime(); } else if (m_running) { // pathological case: we set a strange timeout value that we // can recognize later on if necessary. If we're not connected, // we'll make it a huge timeout and catch that error later // on. timeout = connected ? 9999 : 9999999; WARNING(stderr, "XaoSProducer: m_running but not (connected && ts_running)\n"); } else { WARNING(stderr, "XaoSProducer: ! ts_running\n"); } // Adjust the timeout to make sure it's reasonable. if (timeout <= 0) { // We needed to start handling the next event before now. if ((RunMode() != B_OFFLINE) && (timeout < -50000)) { // We're way behind in a real-time run mode -- // just skip forward in the media to catch up! m_delta -= timeout-5000; } // Give us some breathing room to check for messages. // We don't simply refuse to handle messages when // we're behind so that we can remain responsive even // when our buffer-producing ability is maxed out. timeout = 1000; } //////////////////////////////////////////////////////////// // Step 2: Check for pending messages. // Conveniently enough, if there are no pending messages, // this call to read_port_etc will force our thread to // wait for the length of timeout. Recall, we just set // timeout to be the real time until the next performance // event or buffer production needs to happen, whichever // comes first. int32 code = 0; fprintf(stderr, "XaoS Thread:Waiting for messages\n"); status_t err = read_port_etc(m_port, &code, msg, B_MEDIA_MESSAGE_SIZE, B_TIMEOUT, timeout); fprintf(stderr, "XaoS Thread:message received\n"); // If we received a message, err will be the size of the message (including 0). if (err >= 0) { bad = 0; NODE(stderr, "XaoSProducer msg %#010lx\n", code); // Check for our private stop message. if (code == MSG_QUIT_NOW) { // quit now NODE(stderr, "XaoSProducer quitting\n");#if 0 if (m_notifyHook) { (*m_notifyHook)(m_cookie, B_NODE_DIES, 0); } else { Notify(B_NODE_DIES, 0); }#endif break; } // Else it is hopefully a regular media kit message; go ahead and // dispatch it. (HandleMessage addresses the case that the message // wasn't understood by anybody.) else { HandleMessage(code, msg, err); } } // Timing out means that there was no buffer, which is ok. // Other errors, though, are bad. else if (err != B_TIMED_OUT) { WARNING(stderr, "XaoSProducer::ServiceThread(): port says %#010lx (%s)\n", err, strerror(err)); bad++; // If we receive three bad reads with no good messages in between, // things are probably not going to improve (like the port disappeared // or something) so we call it a day. if (bad > 3) {#if 0 if (m_notifyHook) { (*m_notifyHook)(m_cookie, B_NODE_DIES, bad, err, code, msg); } else { Notify(B_NODE_DIES, bad, err, code, msg); }#endif break; } } else { //////////////////////////////////////////////////////////// // Step 3: Produce and send a buffer bad = 0; if (timeout > 1000000) { // We set a huge timeout when we were running, but the // time source isn't running, and we're not connected? continue; // don't actually play } // Only make a buffer if time is running, and if we are // running, connected, enabled, and can get a buffer. if (ts_running) { if (connected && m_running) { char c[100]; string_for_format(m_output.format,c,100); fprintf(stderr,"Buffer! %s\n",100); BBuffer * buffer = m_buffers->RequestBuffer( m_output.format.u.raw_video.display.line_count*m_output.format.u.raw_video.display.bytes_per_row); fprintf(stderr,"Buffer! OK\n"); if (buffer) { bigtime_t now = TimeSource()->Now(); NODE(stderr, "XaoSProducer making a buffer at %Ld.\n", now); // Whee, we actually get to make a buffer! // Fill the buffer's header fields. buffer->Header()->start_time = buffer_perf; buffer->Header()->size_used = (m_output.format.u.raw_video.display.line_count*m_output.format.u.raw_video.display.bytes_per_row); // If there is a play hook, let the interested party have at it!#if 0 if (m_playHook) { (*m_playHook)(m_cookie, buffer->Header()->start_time-m_delta, buffer->Data(), buffer->Header()->size_used, m_output.format.u.raw_video); } else { Play(buffer->Header()->start_time-m_delta, buffer->Data(), buffer->Header()->size_used, m_output.format.u.raw_video); }#endif // Update our frame counter and send the buffer off! // If the send is successful, the last consumer to use // the buffer will recycle it for us. m_frames_played ++; if (acquire_sem_etc(m_sendBufferSem, 1, B_TIMEOUT, 30000) != B_OK) { WARNING(stderr, "XaoSProducer: couldn't acquire send buffer sem\n"); buffer->Recycle(); } else { if (SendBuffer(buffer, m_output.destination) < B_OK) { // On the other hand, if the send is unsuccessful, // we mustn't forget to recycle the buffer ourselves. buffer->Recycle(); } release_sem(m_sendBufferSem); } } else { // Something has gone screwy with our buffer group. To // avoid spewing lots of debug output, we'll only print // a message once every 256 occurrences. static int32 warning_cnt = 0; if (!(atomic_add(&warning_cnt, 1) & 255)) { WARNING(stderr, "XaoSProducer: RequestBuffer() failed\n"); } } } else { // Time is running, but there's no reason for us to // actually process a buffer, becuase we won't be // sending it -- we're not connected, running, or // we've been told to shut up. We'll fake up timing // values so that our next timeout is as short as // possible. bigtime_t now = TimeSource()->Now(); // Pretend that our next performance is exactly our // latency's worth away (i.e. that we need to start // processing right away). buffer_perf = now+TotalLatency(); // Set m_frames_played based on this value, so that the // top of the next loop will Do the Right Thing.#if 0 m_frames_played = frames_for_duration(m_output.format.u.raw_video, buffer_perf-m_delta);#endif m_frames_played = (int)((buffer_perf - m_delta) * m_output.format.u.raw_video.field_rate / 1000000); } } else { // We can't do anything when time isn't running. TRANSPORT(stderr, "time source is not running\n"); } } }}void XaoSProducer::alloc_buffers(){ delete m_buffers; int size; char fmt[100]; bigtime_t latency = TotalLatency(); int count = (int)(latency * m_output.format.u.raw_video.field_rate / 1000000+ 2); fprintf(stderr,"XaoSProducer:: alloc_buffers (latency:%i count:%i field rate:%i)\n",(int)latency, (int)count, (int)m_output.format.u.raw_video.field_rate); string_for_format(m_output.format, fmt, 100); FORMAT(stderr, "We've decided to use %s\n", fmt); // But if count is too small, we'd like to have three buffers // at the very least, to give us some stability. if (count < 3) count = 3; size = m_output.format.u.raw_video.display.line_count*m_output.format.u.raw_video.display.bytes_per_row;#define MAXSIZE (1024*1024*4) /*Maximal bufer is 4MB*/ if (count*(long long)size > (long long)MAXSIZE) { count = MAXSIZE/size; if (count < 1) count = 1; }#if 0 // We should set a reasonable maximum on the size of our memory // pool. We'll restrict it to 128K. if (count*m_output.format.u.raw_video.buffer_size > 128000) { count = 128000/m_output.format.u.raw_audio.buffer_size; // We do need to make sure there's at least one buffer, though. if (count < 1) count = 1; }#endif NODE(stderr, "Need %d buffers of size %i\n", count, size); m_buffers = new BBufferGroup(size, count);}bigtime_tXaoSProducer::ProcessingLatency(){ /* XaoS attempts to keep framerate higher than 5 frames per second, but sometimes it is imposible */ return (1000000/25);}bigtime_tXaoSProducer::TotalLatency(){ return ProcessingLatency() + m_downstream_latency + m_private_latency;}voidXaoSProducer::Play( bigtime_t /* time */, void * /* data */, size_t /* size */, const media_raw_video_format & /* format */){ // If there is no play hook installed, we instead call this function // for received buffers.}voidXaoSProducer::Notify( int32 /* cause */, ...){ // If there is no notification hook installed, we instead call this function // for giving notification of various events.}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -