it compiles
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1140 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
366a7cf67c
commit
728a8c7497
@ -5,6 +5,7 @@ UsePrivateHeaders demultiplexer ;
|
||||
Addon demultiplexer.media_addon : media :
|
||||
MediaDemultiplexerNode.cpp
|
||||
MediaDemultiplexerAddOn.cpp
|
||||
MediaOutputInfo.cpp
|
||||
misc.cpp
|
||||
;
|
||||
|
||||
|
@ -0,0 +1,161 @@
|
||||
// MediaDemultiplexerAddOn.cpp
|
||||
//
|
||||
// Andrew Bachmann, 2002
|
||||
//
|
||||
// MediaDemultiplexerAddOn is an add-on
|
||||
// that can make instances of MediaDemultiplexerNode
|
||||
//
|
||||
// MediaDemultiplexerNode handles a file and a multistream
|
||||
|
||||
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaAddOn.h>
|
||||
#include <Errors.h>
|
||||
|
||||
#include "MediaDemultiplexerNode.h"
|
||||
#include "MediaDemultiplexerAddOn.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// instantiation function
|
||||
extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image)
|
||||
{
|
||||
return new MediaDemultiplexerAddOn(image);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- //
|
||||
// ctor/dtor
|
||||
// -------------------------------------------------------- //
|
||||
|
||||
MediaDemultiplexerAddOn::~MediaDemultiplexerAddOn()
|
||||
{
|
||||
}
|
||||
|
||||
MediaDemultiplexerAddOn::MediaDemultiplexerAddOn(image_id image) :
|
||||
BMediaAddOn(image)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::MediaDemultiplexerAddOn\n");
|
||||
refCount = 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- //
|
||||
// BMediaAddOn impl
|
||||
// -------------------------------------------------------- //
|
||||
|
||||
status_t MediaDemultiplexerAddOn::InitCheck(
|
||||
const char ** out_failure_text)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::InitCheck\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int32 MediaDemultiplexerAddOn::CountFlavors()
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::CountFlavors\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status_t MediaDemultiplexerAddOn::GetFlavorAt(
|
||||
int32 n,
|
||||
const flavor_info ** out_info)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::GetFlavorAt\n");
|
||||
if (out_info == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE; // we refuse to crash because you were stupid
|
||||
}
|
||||
if (n != 0) {
|
||||
fprintf(stderr,"<- B_BAD_INDEX\n");
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
flavor_info * infos = new flavor_info[1];
|
||||
MediaDemultiplexerNode::GetFlavor(&infos[0],n);
|
||||
(*out_info) = infos;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BMediaNode * MediaDemultiplexerAddOn::InstantiateNodeFor(
|
||||
const flavor_info * info,
|
||||
BMessage * config,
|
||||
status_t * out_error)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::InstantiateNodeFor\n");
|
||||
if (out_error == 0) {
|
||||
fprintf(stderr,"<- NULL\n");
|
||||
return 0; // we refuse to crash because you were stupid
|
||||
}
|
||||
MediaDemultiplexerNode * node
|
||||
= new MediaDemultiplexerNode(info,config,this);
|
||||
if (node == 0) {
|
||||
*out_error = B_NO_MEMORY;
|
||||
fprintf(stderr,"<- B_NO_MEMORY\n");
|
||||
} else {
|
||||
*out_error = node->InitCheck();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
status_t MediaDemultiplexerAddOn::GetConfigurationFor(
|
||||
BMediaNode * your_node,
|
||||
BMessage * into_message)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::GetConfigurationFor\n");
|
||||
if (into_message == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE; // we refuse to crash because you were stupid
|
||||
}
|
||||
MediaDemultiplexerNode * node
|
||||
= dynamic_cast<MediaDemultiplexerNode*>(your_node);
|
||||
if (node == 0) {
|
||||
fprintf(stderr,"<- B_BAD_TYPE\n");
|
||||
return B_BAD_TYPE;
|
||||
}
|
||||
return node->GetConfigurationFor(into_message);
|
||||
}
|
||||
|
||||
bool MediaDemultiplexerAddOn::WantsAutoStart()
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::WantsAutoStart\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
status_t MediaDemultiplexerAddOn::AutoStart(
|
||||
int in_count,
|
||||
BMediaNode ** out_node,
|
||||
int32 * out_internal_id,
|
||||
bool * out_has_more)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerAddOn::AutoStart\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- //
|
||||
// main
|
||||
// -------------------------------------------------------- //
|
||||
|
||||
// int main(int argc, char *argv[])
|
||||
//{
|
||||
//}
|
||||
|
||||
// -------------------------------------------------------- //
|
||||
// stuffing
|
||||
// -------------------------------------------------------- //
|
||||
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_0(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_1(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_2(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_3(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_4(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_5(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_6(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_7(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_8(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_9(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_10(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_11(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_12(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_13(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_14(void *) {};
|
||||
status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_15(void *) {};
|
@ -34,11 +34,6 @@ MediaDemultiplexerNode::~MediaDemultiplexerNode(void)
|
||||
fprintf(stderr,"MediaDemultiplexerNode::~MediaDemultiplexerNode\n");
|
||||
// Stop the BMediaEventLooper thread
|
||||
Quit();
|
||||
if (fBufferGroup != 0) {
|
||||
BBufferGroup * group = fBufferGroup;
|
||||
fBufferGroup = 0;
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
MediaDemultiplexerNode::MediaDemultiplexerNode(
|
||||
@ -48,7 +43,7 @@ MediaDemultiplexerNode::MediaDemultiplexerNode(
|
||||
: BMediaNode("MediaDemultiplexerNode"),
|
||||
BMediaEventLooper(),
|
||||
BBufferConsumer(B_MEDIA_MULTISTREAM),
|
||||
BBufferProducer(B_MEDIA_UNKNOWN) // no B_MEDIA_ANY
|
||||
BBufferProducer(B_MEDIA_UNKNOWN_TYPE) // no B_MEDIA_ANY
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerNode::MediaDemultiplexerNode\n");
|
||||
// keep our creator around for AddOn calls later
|
||||
@ -550,7 +545,7 @@ status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n");
|
||||
// let's not crash even if they are stupid
|
||||
if ((out_output == 0) || (oookie == 0)) {
|
||||
if ((out_output == 0) || (cookie == 0)) {
|
||||
// no place to write!
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE;
|
||||
@ -572,7 +567,7 @@ status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */
|
||||
// return this output
|
||||
*out_output = itr->output;
|
||||
// so next time they won't get the same output again
|
||||
*cookie = (int32)itr.next();
|
||||
*cookie = (int32)++itr;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -592,7 +587,7 @@ status_t MediaDemultiplexerNode::SetBufferGroup(
|
||||
// find the information for this output
|
||||
vector<MediaOutputInfo>::iterator itr;
|
||||
for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
|
||||
if (itr->output.source == source) {
|
||||
if (itr->output.source == for_source) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -649,7 +644,7 @@ status_t MediaDemultiplexerNode::PrepareToConnect(
|
||||
// find the information for this output
|
||||
vector<MediaOutputInfo>::iterator itr;
|
||||
for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
|
||||
if (itr->output.source == source) {
|
||||
if (itr->output.source == what) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -658,7 +653,7 @@ status_t MediaDemultiplexerNode::PrepareToConnect(
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
|
||||
return B_MEDIA_BAD_SOURCE;
|
||||
}
|
||||
return itr->PrepareToConnect(destination,format,out_source,out_name);
|
||||
return itr->PrepareToConnect(where,format,out_source,out_name);
|
||||
}
|
||||
|
||||
void MediaDemultiplexerNode::Connect(
|
||||
@ -669,12 +664,6 @@ void MediaDemultiplexerNode::Connect(
|
||||
char * io_name)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerNode::Connect\n");
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr,"<- error already\n");
|
||||
output.destination = media_destination::null;
|
||||
GetFormat(&output.format);
|
||||
return;
|
||||
}
|
||||
// find the information for this output
|
||||
vector<MediaOutputInfo>::iterator itr;
|
||||
for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
|
||||
@ -687,68 +676,82 @@ void MediaDemultiplexerNode::Connect(
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr,"<- error already\n");
|
||||
itr->output.destination = media_destination::null;
|
||||
itr->output.format = itr->generalFormat;
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate the downstream latency
|
||||
// must happen before itr->Connect
|
||||
bigtime_t downstreamLatency;
|
||||
media_node_id id;
|
||||
FindLatencyFor(itr->output.destination, &downstreamLatency, &id);
|
||||
|
||||
// record the agreed upon values
|
||||
status_t status;
|
||||
status = itr->Connect(destination,format,io_name);
|
||||
status = itr->Connect(destination,format,io_name,downstreamLatency);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr," itr->Connect returned an error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// // compute the buffer period (must be done before setbuffergroup)
|
||||
// fBufferPeriod = bigtime_t(1000 * 8000000 / 1024
|
||||
// * output.format.u.multistream.max_chunk_size
|
||||
// / output.format.u.multistream.max_bit_rate);
|
||||
//
|
||||
// fprintf(stderr," max chunk size = %i, max bit rate = %f, buffer period = %lld\n",
|
||||
// output.format.u.multistream.max_chunk_size,
|
||||
// output.format.u.multistream.max_bit_rate,fBufferPeriod);
|
||||
//
|
||||
// SetBufferDuration(fBufferPeriod);
|
||||
|
||||
if (GetCurrentFile() != 0) {
|
||||
bigtime_t start, end;
|
||||
uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size
|
||||
BBuffer * buffer = 0;
|
||||
ssize_t bytesRead = 0;
|
||||
{ // timed section
|
||||
start = TimeSource()->RealTime();
|
||||
// first we try to use a real BBuffer
|
||||
buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
|
||||
if (buffer != 0) {
|
||||
FillFileBuffer(buffer);
|
||||
} else {
|
||||
// didn't get a real BBuffer, try simulation by just a read from the disk
|
||||
bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size);
|
||||
}
|
||||
end = TimeSource()->RealTime();
|
||||
}
|
||||
bytesRead = buffer->SizeUsed();
|
||||
delete data;
|
||||
if (buffer != 0) {
|
||||
buffer->Recycle();
|
||||
}
|
||||
GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it
|
||||
|
||||
fInternalLatency = end - start;
|
||||
|
||||
fprintf(stderr," internal latency from disk read = %lld\n",fInternalLatency);
|
||||
} else {
|
||||
fInternalLatency = 100; // just guess
|
||||
fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency);
|
||||
// compute the internal latency
|
||||
// must happen after itr->Connect
|
||||
if (fInternalLatency == 0) {
|
||||
fInternalLatency = 100; // temporary until we finish computing it
|
||||
ComputeInternalLatency();
|
||||
}
|
||||
|
||||
// If the downstream latency for this output is larger
|
||||
// than our current downstream latency, we have to increase
|
||||
// our current downstream latency to be the larger value.
|
||||
if (itr->downstreamLatency > fDownstreamLatency) {
|
||||
fDownstreamLatency = itr->downstreamLatency;
|
||||
if (downstreamLatency > fDownstreamLatency) {
|
||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||
}
|
||||
|
||||
// XXX: what do I set the buffer duration to?
|
||||
// it depends on which output is sending!!
|
||||
// SetBufferDuration(bufferPeriod);
|
||||
|
||||
// XXX: do anything else?
|
||||
return B_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
void MediaDemultiplexerNode::ComputeInternalLatency() {
|
||||
fprintf(stderr,"MediaDemultiplexerNode::ComputeInternalLatency\n");
|
||||
// if (GetCurrentFile() != 0) {
|
||||
// bigtime_t start, end;
|
||||
// uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size
|
||||
// BBuffer * buffer = 0;
|
||||
// ssize_t bytesRead = 0;
|
||||
// { // timed section
|
||||
// start = TimeSource()->RealTime();
|
||||
// // first we try to use a real BBuffer
|
||||
// buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
|
||||
// if (buffer != 0) {
|
||||
// FillFileBuffer(buffer);
|
||||
// } else {
|
||||
// // didn't get a real BBuffer, try simulation by just a read from the disk
|
||||
// bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size);
|
||||
// }
|
||||
// end = TimeSource()->RealTime();
|
||||
// }
|
||||
// bytesRead = buffer->SizeUsed();
|
||||
// delete data;
|
||||
// if (buffer != 0) {
|
||||
// buffer->Recycle();
|
||||
// }
|
||||
// GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it
|
||||
//
|
||||
// fInternalLatency = end - start;
|
||||
//
|
||||
// fprintf(stderr," internal latency from disk read = %lld\n",fInternalLatency);
|
||||
// } else {
|
||||
fInternalLatency = 100; // just guess
|
||||
fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency);
|
||||
// }
|
||||
}
|
||||
|
||||
void MediaDemultiplexerNode::Disconnect(
|
||||
@ -756,10 +759,6 @@ void MediaDemultiplexerNode::Disconnect(
|
||||
const media_destination & where)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerNode::Disconnect\n");
|
||||
if (output.destination != where) {
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
|
||||
return;
|
||||
}
|
||||
// find the information for this output
|
||||
vector<MediaOutputInfo>::iterator itr;
|
||||
for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
|
||||
@ -772,6 +771,10 @@ void MediaDemultiplexerNode::Disconnect(
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
|
||||
return;
|
||||
}
|
||||
if (itr->output.destination != where) {
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
|
||||
return;
|
||||
}
|
||||
// if this output has an equal (or higher!) latency than
|
||||
// our current believed downstream latency, we may have to
|
||||
// update our downstream latency.
|
||||
@ -796,30 +799,39 @@ void MediaDemultiplexerNode::LateNoticeReceived(
|
||||
bigtime_t performance_time)
|
||||
{
|
||||
fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived\n");
|
||||
if (what == output.source) {
|
||||
switch (RunMode()) {
|
||||
case B_OFFLINE:
|
||||
// nothing to do
|
||||
break;
|
||||
case B_RECORDING:
|
||||
// nothing to do
|
||||
break;
|
||||
case B_INCREASE_LATENCY:
|
||||
fInternalLatency += how_much;
|
||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||
break;
|
||||
case B_DECREASE_PRECISION:
|
||||
// what to do?
|
||||
break;
|
||||
case B_DROP_DATA:
|
||||
// what to do?
|
||||
break;
|
||||
default:
|
||||
// huh?? there aren't any more run modes.
|
||||
fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n");
|
||||
break;
|
||||
vector<MediaOutputInfo>::iterator itr;
|
||||
for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
|
||||
if (itr->output.source == what) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (itr == outputs.end()) {
|
||||
// we don't have that output
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
|
||||
return;
|
||||
}
|
||||
switch (RunMode()) {
|
||||
case B_OFFLINE:
|
||||
// nothing to do
|
||||
break;
|
||||
case B_RECORDING:
|
||||
// nothing to do
|
||||
break;
|
||||
case B_INCREASE_LATENCY:
|
||||
fInternalLatency += how_much;
|
||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||
break;
|
||||
case B_DECREASE_PRECISION:
|
||||
// XXX: try to catch up by producing buffers faster
|
||||
break;
|
||||
case B_DROP_DATA:
|
||||
// XXX: should we really drop buffers? just for that output?
|
||||
break;
|
||||
default:
|
||||
// huh?? there aren't any more run modes.
|
||||
fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDemultiplexerNode::EnableOutput(
|
||||
@ -865,7 +877,7 @@ void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved
|
||||
// find the information for this output
|
||||
vector<MediaOutputInfo>::iterator itr;
|
||||
for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
|
||||
if (itr->output.source == what) {
|
||||
if (itr->output.source == source) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -875,12 +887,11 @@ void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved
|
||||
return;
|
||||
}
|
||||
BBuffer * buffer;
|
||||
status_t status = GetFilledBuffer(*itr,&buffer);
|
||||
status_t status = itr->AdditionalBufferRequested(prev_buffer,prev_time,prev_tag);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested got an error from GetFilledBuffer.\n");
|
||||
return; // don't send the buffer
|
||||
fprintf(stderr," itr->AdditionalBufferRequested returned an error.\n");
|
||||
return;
|
||||
}
|
||||
SendBuffer(buffer,itr->output.destination);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1067,7 +1078,7 @@ status_t MediaDemultiplexerNode::HandleBuffer(
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
bigtime_t nextEventTime = event->event_time+fBufferPeriod;
|
||||
bigtime_t nextEventTime = event->event_time+10000; // fBufferPeriod; // XXX : should multiply
|
||||
media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER);
|
||||
EventQueue()->AddEvent(nextBufferEvent);
|
||||
return status;
|
||||
|
@ -320,6 +320,11 @@ virtual status_t HandleParameter(
|
||||
bigtime_t lateness,
|
||||
bool realTimeEvent = false);
|
||||
|
||||
protected:
|
||||
|
||||
void CreateBufferGroup(MediaOutputInfo * output_info);
|
||||
void ComputeInternalLatency();
|
||||
|
||||
public:
|
||||
|
||||
static void GetFlavor(flavor_info * outInfo, int32 id);
|
||||
|
@ -0,0 +1,282 @@
|
||||
// MediaOutputInfo.cpp
|
||||
//
|
||||
// Andrew Bachmann, 2002
|
||||
//
|
||||
// A class to encapsulate and manipulate
|
||||
// all the information for a particular
|
||||
// output of a media node.
|
||||
|
||||
#include <MediaDefs.h>
|
||||
#include <BufferGroup.h>
|
||||
#include <BufferProducer.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "MediaOutputInfo.h"
|
||||
#include "misc.h"
|
||||
|
||||
MediaOutputInfo::MediaOutputInfo(BBufferProducer * node, char * name) {
|
||||
producer = node;
|
||||
// null some fields
|
||||
bufferGroup = 0;
|
||||
bufferPeriod = 0;
|
||||
// start enabled
|
||||
outputEnabled = true;
|
||||
// don't overwrite available space, and be sure to terminate
|
||||
strncpy(output.name,name,B_MEDIA_NAME_LENGTH-1);
|
||||
output.name[B_MEDIA_NAME_LENGTH-1] = '\0';
|
||||
// initialize the output
|
||||
output.node = media_node::null;
|
||||
output.source = media_source::null;
|
||||
output.destination = media_destination::null;
|
||||
}
|
||||
|
||||
MediaOutputInfo::~MediaOutputInfo() {
|
||||
if (bufferGroup != 0) {
|
||||
BBufferGroup * group = bufferGroup;
|
||||
bufferGroup = 0;
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
status_t MediaOutputInfo::SetBufferGroup(BBufferGroup * group) {
|
||||
if (bufferGroup != 0) {
|
||||
if (bufferGroup == group) {
|
||||
return B_OK; // time saver
|
||||
}
|
||||
delete bufferGroup;
|
||||
}
|
||||
bufferGroup = group;
|
||||
}
|
||||
|
||||
// They made an offer to us. We should make sure that the offer is
|
||||
// acceptable, and then we can add any requirements we have on top of
|
||||
// that. We leave wildcards for anything that we don't care about.
|
||||
status_t MediaOutputInfo::FormatProposal(media_format * format)
|
||||
{
|
||||
if (format == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE; // no crashing
|
||||
}
|
||||
// Be's format_is_compatible doesn't work,
|
||||
// so use our format_is_acceptible instead
|
||||
if (!format_is_acceptible(*format,generalFormat)) {
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
// XXX: test because we don't trust them!
|
||||
format->SpecializeTo(&wildcardedFormat);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Presumably we have already agreed with them that this format is
|
||||
// okay. But just in case, we check the offer. (and complain if it
|
||||
// is invalid) Then as the last thing we do, we get rid of any
|
||||
// remaining wilcards.
|
||||
status_t MediaOutputInfo::FormatChangeRequested(const media_destination & destination,
|
||||
media_format * io_format)
|
||||
{
|
||||
if (io_format == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE; // no crashing
|
||||
}
|
||||
status_t status = FormatProposal(io_format);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"<- MediaOutputInfo::FormatProposal failed\n");
|
||||
*io_format = generalFormat;
|
||||
return status;
|
||||
}
|
||||
io_format->SpecializeTo(&fullySpecifiedFormat);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t MediaOutputInfo::PrepareToConnect(const media_destination & where,
|
||||
media_format * format,
|
||||
media_source * out_source,
|
||||
char * out_name)
|
||||
{
|
||||
if (output.destination != media_destination::null) {
|
||||
fprintf(stderr,"<- B_MEDIA_ALREADY_CONNECTED\n");
|
||||
return B_MEDIA_ALREADY_CONNECTED;
|
||||
}
|
||||
status_t status = FormatChangeRequested(where,format);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"<- MediaOutputInfo::FormatChangeRequested failed\n");
|
||||
return status;
|
||||
}
|
||||
*out_source = output.source;
|
||||
output.destination = where;
|
||||
strncpy(out_name,output.name,B_MEDIA_NAME_LENGTH-1);
|
||||
out_name[B_MEDIA_NAME_LENGTH] = '\0';
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t MediaOutputInfo::Connect(const media_destination & destination,
|
||||
const media_format & format,
|
||||
char * io_name,
|
||||
bigtime_t _downstreamLatency)
|
||||
{
|
||||
if (io_name == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
output.destination = destination;
|
||||
output.format = format;
|
||||
strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1);
|
||||
io_name[B_MEDIA_NAME_LENGTH-1] = '\0';
|
||||
downstreamLatency = _downstreamLatency; // must be set before create buffer group
|
||||
|
||||
status_t status = CreateBufferGroup(); // also initializes buffer period
|
||||
if (status != B_OK) {
|
||||
output.destination = media_destination::null;
|
||||
output.format = generalFormat;
|
||||
return status;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t MediaOutputInfo::Disconnect()
|
||||
{
|
||||
output.destination = media_destination::null;
|
||||
output.format = generalFormat;
|
||||
if (bufferGroup != 0) {
|
||||
BBufferGroup * group = bufferGroup;
|
||||
bufferGroup = 0;
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
status_t MediaOutputInfo::EnableOutput(bool enabled)
|
||||
{
|
||||
outputEnabled = enabled;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t MediaOutputInfo::AdditionalBufferRequested(
|
||||
media_buffer_id prev_buffer,
|
||||
bigtime_t prev_time,
|
||||
const media_seek_tag * prev_tag)
|
||||
{
|
||||
// XXX: implement me
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// protected:
|
||||
|
||||
status_t MediaOutputInfo::CreateBufferGroup() {
|
||||
bufferPeriod = ComputeBufferPeriod();
|
||||
|
||||
if (bufferGroup == 0) {
|
||||
int32 count = int32(downstreamLatency/bufferPeriod)+2;
|
||||
fprintf(stderr," downstream latency = %lld, buffer period = %lld, buffer count = %i\n",
|
||||
downstreamLatency,bufferPeriod,count);
|
||||
|
||||
// allocate the buffers
|
||||
bufferGroup = new BBufferGroup(ComputeBufferSize(),count);
|
||||
if (bufferGroup == 0) {
|
||||
fprintf(stderr,"<- B_NO_MEMORY\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
status_t status = bufferGroup->InitCheck();
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"<- BufferGroup initialization failed\n");
|
||||
BBufferGroup * group = bufferGroup;
|
||||
bufferGroup = 0;
|
||||
delete group;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// public:
|
||||
|
||||
uint32 MediaOutputInfo::ComputeBufferSize() {
|
||||
return ComputeBufferSize(output.format);
|
||||
}
|
||||
|
||||
// returns result in # of bytes
|
||||
uint32 MediaOutputInfo::ComputeBufferSize(const media_format & format) {
|
||||
uint64 bufferSize = 1024; // default 1024 bytes
|
||||
switch (format.type) {
|
||||
case B_MEDIA_MULTISTREAM:
|
||||
bufferSize = format.u.multistream.max_chunk_size;
|
||||
break;
|
||||
case B_MEDIA_ENCODED_VIDEO:
|
||||
bufferSize = format.u.encoded_video.frame_size;
|
||||
break;
|
||||
case B_MEDIA_RAW_VIDEO:
|
||||
if (format.u.raw_video.interlace == 0) {
|
||||
// okay, you have no fields, you need no space, right?
|
||||
bufferSize = 0;
|
||||
} else {
|
||||
// this is the size of a *field*, not a frame
|
||||
bufferSize = format.u.raw_video.display.bytes_per_row *
|
||||
format.u.raw_video.display.line_count /
|
||||
format.u.raw_video.interlace;
|
||||
}
|
||||
break;
|
||||
case B_MEDIA_ENCODED_AUDIO:
|
||||
bufferSize = format.u.encoded_audio.frame_size;
|
||||
break;
|
||||
case B_MEDIA_RAW_AUDIO:
|
||||
bufferSize = format.u.raw_audio.buffer_size;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (bufferSize > INT_MAX) {
|
||||
bufferSize = INT_MAX;
|
||||
}
|
||||
return int32(bufferSize);
|
||||
}
|
||||
|
||||
bigtime_t MediaOutputInfo::ComputeBufferPeriod() {
|
||||
return ComputeBufferPeriod(output.format);
|
||||
}
|
||||
|
||||
// returns result in # of microseconds
|
||||
bigtime_t MediaOutputInfo::ComputeBufferPeriod(const media_format & format) {
|
||||
bigtime_t bufferPeriod = 25*1000; // default 25 milliseconds
|
||||
switch (format.type) {
|
||||
case B_MEDIA_MULTISTREAM:
|
||||
// given a buffer size of 8192 bytes
|
||||
// and a bitrate of 1024 kilobits/millisecond (= 128 bytes/millisecond)
|
||||
// we need to produce a buffer every 64 milliseconds (= every 64000 microseconds)
|
||||
bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format)
|
||||
/ format.u.multistream.max_bit_rate);
|
||||
break;
|
||||
case B_MEDIA_ENCODED_VIDEO:
|
||||
bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format)
|
||||
/ format.u.encoded_video.max_bit_rate);
|
||||
break;
|
||||
case B_MEDIA_ENCODED_AUDIO:
|
||||
bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format)
|
||||
/ format.u.encoded_audio.bit_rate);
|
||||
break;
|
||||
case B_MEDIA_RAW_VIDEO:
|
||||
// Given a field rate of 50.00 fields per second, (PAL)
|
||||
// we need to generate a field/buffer
|
||||
// every 1/50 of a second = 20000 microseconds.
|
||||
bufferPeriod = bigtime_t(1000000.0
|
||||
/ format.u.raw_video.field_rate);
|
||||
break;
|
||||
case B_MEDIA_RAW_AUDIO:
|
||||
// Given a sample size of 4 bytes [B_AUDIO_INT]
|
||||
// and a channel count of 2 and a buffer_size
|
||||
// of 256 bytes and a frame_rate of 44100 Hertz (1/sec)
|
||||
// 1 frame = 1 sample/channel.
|
||||
// comes to ??
|
||||
// this is a guess:
|
||||
bufferPeriod = bigtime_t(1000000.0 * ComputeBufferSize(format)
|
||||
/ (format.u.raw_audio.format
|
||||
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
||||
/ format.u.raw_audio.channel_count
|
||||
/ format.u.raw_audio.frame_rate);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return bufferPeriod;
|
||||
}
|
||||
|
||||
|
@ -10,188 +10,59 @@
|
||||
#define _MEDIA_OUTPUT_INFO_H
|
||||
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaNode.h>
|
||||
#include <BufferProducer.h>
|
||||
#include <BufferGroup.h>
|
||||
|
||||
class MediaOutputInfo
|
||||
{
|
||||
public:
|
||||
MediaOutputInfo(char * name) {
|
||||
// null some fields
|
||||
bufferGroup = 0;
|
||||
// start enabled
|
||||
outputEnabled = true;
|
||||
// don't overwrite available space, and be sure to terminate
|
||||
strncpy(output.name,name,B_MEDIA_NAME_LENGTH-1);
|
||||
output.name[B_MEDIA_NAME_LENGTH-1] = '\0';
|
||||
// initialize the output
|
||||
output.node = media_node::null;
|
||||
output.source = media_source::null;
|
||||
output.destination = media_source::null;
|
||||
}
|
||||
~MediaOutputInfo() {
|
||||
if (bufferGroup != 0) {
|
||||
BBufferGroup * group = bufferGroup;
|
||||
bufferGroup = 0;
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
SetBufferGroup(BBufferGroup * group) {
|
||||
// if (fBufferGroup != 0) {
|
||||
// if (fBufferGroup == group) {
|
||||
// return B_OK; // time saver
|
||||
// }
|
||||
// delete fBufferGroup;
|
||||
// }
|
||||
// if (group != 0) {
|
||||
// fBufferGroup = group;
|
||||
// } else {
|
||||
// // let's take advantage of this opportunity to recalculate
|
||||
// // our downstream latency and ensure that it is up to date
|
||||
// media_node_id id;
|
||||
// FindLatencyFor(output.destination, &fDownstreamLatency, &id);
|
||||
// // buffer period gets initialized in Connect() because
|
||||
// // that is the first time we get the real values for
|
||||
// // chunk size and bit rate, which are used to compute buffer period
|
||||
// // note: you can still make a buffer group before connecting (why?)
|
||||
// // but we don't make it, you make it yourself and pass it here.
|
||||
// // not sure why anybody would want to do that since they need
|
||||
// // a connection anyway...
|
||||
// if (fBufferPeriod <= 0) {
|
||||
// fprintf(stderr,"<- B_NO_INIT");
|
||||
// return B_NO_INIT;
|
||||
// }
|
||||
// int32 count = int32(fDownstreamLatency/fBufferPeriod)+2;
|
||||
// fprintf(stderr," downstream latency = %lld, buffer period = %lld, buffer count = %i\n",
|
||||
// fDownstreamLatency,fBufferPeriod,count);
|
||||
//
|
||||
// // allocate the buffers
|
||||
// fBufferGroup = new BBufferGroup(output.format.u.multistream.max_chunk_size,count);
|
||||
// if (fBufferGroup == 0) {
|
||||
// fprintf(stderr,"<- B_NO_MEMORY\n");
|
||||
// return B_NO_MEMORY;
|
||||
// }
|
||||
// status_t status = fBufferGroup->InitCheck();
|
||||
// if (status != B_OK) {
|
||||
// fprintf(stderr,"<- fBufferGroup initialization failed\n");
|
||||
// return status;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// They made an offer to us. We should make sure that the offer is
|
||||
// acceptable, and then we can add any requirements we have on top of
|
||||
// that. We leave wildcards for anything that we don't care about.
|
||||
status_t FormatProposal(media_format * format)
|
||||
{
|
||||
if (format == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE; // no crashing
|
||||
}
|
||||
// Be's format_is_compatible doesn't work,
|
||||
// so use our format_is_acceptible instead
|
||||
if (!format_is_acceptible(*format,generalFormat)) {
|
||||
fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
// XXX: test because we don't trust them!
|
||||
format->SpecializeTo(wildcardedFormat);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Presumably we have already agreed with them that this format is
|
||||
// okay. But just in case, we check the offer. (and complain if it
|
||||
// is invalid) Then as the last thing we do, we get rid of any
|
||||
// remaining wilcards.
|
||||
status_t FormatChangeRequested(const media_destination & destination,
|
||||
media_format * io_format)
|
||||
{
|
||||
if (io_format == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE; // no crashing
|
||||
}
|
||||
status_t status = FormatProposal(io_format);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"<- MediaOutputInfo::FormatProposal failed\n");
|
||||
*io_format = generalFormat;
|
||||
return status;
|
||||
}
|
||||
io_format->SpecializeTo(fullySpecifiedFormat);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t PrepareToConnect(const media_destination & where,
|
||||
media_format * format,
|
||||
media_source * out_source,
|
||||
char * out_name)
|
||||
{
|
||||
if (output.destination != media_destination::null) {
|
||||
fprintf(stderr,"<- B_MEDIA_ALREADY_CONNECTED\n");
|
||||
return B_MEDIA_ALREADY_CONNECTED;
|
||||
}
|
||||
status_t status = FormatChangeRequested(where,format,out_name);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"<- MediaOutputInfo::FormatChangeRequested failed\n");
|
||||
return status;
|
||||
}
|
||||
*out_source = output.source;
|
||||
output.destination = where;
|
||||
strncpy(out_name,output.name,B_MEDIA_NAME_LENGTH-1);
|
||||
out_name[B_MEDIA_NAME_LENGTH] = '\0';
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t Connect(const media_destination & destination,
|
||||
const media_format & format,
|
||||
char * io_name)
|
||||
{
|
||||
if (io_name == 0) {
|
||||
fprintf(stderr,"<- B_BAD_VALUE\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
output.destination = destination;
|
||||
output.format = format;
|
||||
strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1);
|
||||
io_name[B_MEDIA_NAME_LENGTH-1] = '\0';
|
||||
MediaOutputInfo(BBufferProducer * _node, char * name);
|
||||
~MediaOutputInfo();
|
||||
|
||||
// determine our downstream latency
|
||||
media_node_id id;
|
||||
FindLatencyFor(output.destination, &downstreamLatency, &id);
|
||||
virtual status_t SetBufferGroup(BBufferGroup * group);
|
||||
|
||||
// compute the buffer period (must be done before setbuffergroup)
|
||||
bufferPeriod = computeBufferPeriod(output.format);
|
||||
SetBufferDuration(fBufferPeriod);
|
||||
virtual status_t FormatProposal(media_format * format);
|
||||
|
||||
// setup the buffers if they aren't setup yet
|
||||
if (bufferGroup == 0) {
|
||||
status_t status = SetBufferGroup(output.source,0);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,"<- SetBufferGroup failed\n");
|
||||
output.destination = media_destination::null;
|
||||
output.format = generalFormat;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
virtual status_t FormatChangeRequested(
|
||||
const media_destination & destination,
|
||||
media_format * io_format);
|
||||
|
||||
status_t Disconnect()
|
||||
{
|
||||
output.destination = media_destination::null;
|
||||
output.format = genericFormat;
|
||||
if (bufferGroup != 0) {
|
||||
BBufferGroup * group = bufferGroup;
|
||||
bufferGroup = 0;
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
virtual status_t PrepareToConnect(
|
||||
const media_destination & where,
|
||||
media_format * format,
|
||||
media_source * out_source,
|
||||
char * out_name);
|
||||
|
||||
status_t EnableOutput(bool enabled)
|
||||
{
|
||||
outputEnabled = enabled;
|
||||
return B_OK;
|
||||
}
|
||||
virtual status_t Connect(
|
||||
const media_destination & destination,
|
||||
const media_format & format,
|
||||
char * io_name,
|
||||
bigtime_t _downstreamLatency);
|
||||
|
||||
virtual status_t Disconnect();
|
||||
|
||||
virtual status_t EnableOutput(bool enabled);
|
||||
|
||||
virtual status_t AdditionalBufferRequested(
|
||||
media_buffer_id prev_buffer,
|
||||
bigtime_t prev_time,
|
||||
const media_seek_tag * prev_tag);
|
||||
|
||||
protected:
|
||||
|
||||
virtual status_t CreateBufferGroup();
|
||||
|
||||
public:
|
||||
|
||||
virtual uint32 ComputeBufferSize();
|
||||
virtual bigtime_t ComputeBufferPeriod();
|
||||
static uint32 ComputeBufferSize(const media_format & format);
|
||||
static bigtime_t ComputeBufferPeriod(const media_format & format);
|
||||
|
||||
public:
|
||||
BBufferProducer * producer;
|
||||
|
||||
media_output output;
|
||||
|
||||
bool outputEnabled;
|
||||
@ -220,7 +91,7 @@ public:
|
||||
media_format fullySpecifiedFormat;
|
||||
|
||||
// do we need media_seek_tag in here?
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _MEDIA_OUTPUT_INFO_H
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user