it compiles

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1140 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty 2002-09-24 02:25:35 +00:00
parent 366a7cf67c
commit 728a8c7497
6 changed files with 597 additions and 266 deletions

View File

@ -5,6 +5,7 @@ UsePrivateHeaders demultiplexer ;
Addon demultiplexer.media_addon : media :
MediaDemultiplexerNode.cpp
MediaDemultiplexerAddOn.cpp
MediaOutputInfo.cpp
misc.cpp
;

View File

@ -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 *) {};

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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