#include <MediaDefs.h>
#include <MediaNode.h>
#include <MediaAddOn.h>
#include <BufferConsumer.h>
#include <FileInterface.h>
#include <Controllable.h>
#include <MediaEventLooper.h>
#include <File.h>
#include <Errors.h>
#include <Entry.h>
#include <BufferGroup.h>
#include <TimeSource.h>
#include <Buffer.h>
#include <ParameterWeb.h>
#include <MediaRoster.h>
#include <limits.h>
#include "../AbstractFileInterfaceNode.h"
#include "MediaWriter.h"
#include "../misc.h"
#include <stdio.h>
#include <string.h>
MediaWriter::~MediaWriter(void)
{
fprintf(stderr,"MediaWriter::~MediaWriter\n");
if (fBufferGroup != 0) {
BBufferGroup * group = fBufferGroup;
fBufferGroup = 0;
delete group;
}
}
MediaWriter::MediaWriter(
size_t defaultChunkSize,
float defaultBitRate,
const flavor_info * info,
BMessage * config,
BMediaAddOn * addOn)
: BMediaNode("MediaWriter"),
BBufferConsumer(B_MEDIA_MULTISTREAM),
AbstractFileInterfaceNode(defaultChunkSize,defaultBitRate,info,config,addOn)
{
fprintf(stderr,"MediaWriter::MediaWriter\n");
fBufferGroup = 0;
strncpy(input.name,"MediaWriter Input",B_MEDIA_NAME_LENGTH-1);
input.name[B_MEDIA_NAME_LENGTH-1] = '\0';
input.node = media_node::null;
input.source = media_source::null;
input.destination = media_destination::null;
GetFormat(&input.format);
}
void MediaWriter::Preroll(void)
{
fprintf(stderr,"MediaWriter::Preroll\n");
BMediaNode::Preroll();
}
status_t MediaWriter::HandleMessage(
int32 message,
const void * data,
size_t size)
{
fprintf(stderr,"MediaWriter::HandleMessage\n");
status_t status = B_OK;
switch (message) {
default:
status = BBufferConsumer::HandleMessage(message,data,size);
if (status == B_OK) {
break;
}
status = AbstractFileInterfaceNode::HandleMessage(message,data,size);
break;
}
return status;
}
void MediaWriter::NodeRegistered(void)
{
fprintf(stderr,"MediaWriter::NodeRegistered\n");
input.node = Node();
input.destination.id = 0;
input.destination.port = input.node.port;
AbstractFileInterfaceNode::NodeRegistered();
}
status_t MediaWriter::SetRef(
const entry_ref & file,
bool create,
bigtime_t * out_time)
{
fprintf(stderr,"MediaWriter::SetRef\n");
status_t status;
status = AbstractFileInterfaceNode::SetRef(file,B_WRITE_ONLY,create,out_time);
if (status != B_OK) {
fprintf(stderr,"AbstractFileInterfaceNode::SetRef returned an error\n");
return status;
}
if (input.source == media_source::null) {
GetFormat(&input.format);
AddRequirements(&input.format);
return B_OK;
}
media_format format;
GetFormat(&format);
AddRequirements(&format);
if (format_is_acceptible(input.format,format)) {
fprintf(stderr," compatible format = no re-negotiation necessary\n");
return B_OK;
}
BMediaRoster * roster = BMediaRoster::Roster(&status);
if (roster == 0) {
return B_MEDIA_SYSTEM_FAILURE;
}
if (status != B_OK) {
return status;
}
run_state destinationRunState = run_state(RunState());
if (destinationRunState == BMediaEventLooper::B_STARTED) {
Stop(0,true);
}
media_source inputSource = input.source;
status = roster->Disconnect(input.source.id,input.source,
input.destination.id,input.destination);
if (status != B_OK) {
return status;
}
media_output connectOutput;
media_input connectInput;
status = roster->Connect(inputSource,input.destination,
&format,&connectOutput,&connectInput);
if (status != B_OK) {
return status;
}
if (destinationRunState == BMediaEventLooper::B_STARTED) {
Start(0);
}
return status;
}
status_t MediaWriter::AcceptFormat(
const media_destination & dest,
media_format * format)
{
fprintf(stderr,"MediaWriter::AcceptFormat\n");
if (format == 0) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if (input.destination != dest) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION");
return B_MEDIA_BAD_DESTINATION;
}
media_format myFormat;
GetFormat(&myFormat);
if (!format_is_acceptible(*format,myFormat)) {
fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
return B_MEDIA_BAD_FORMAT;
}
AddRequirements(format);
return B_OK;
}
status_t MediaWriter::GetNextInput(
int32 * cookie,
media_input * out_input)
{
fprintf(stderr,"MediaWriter::GetNextInput\n");
if (out_input == 0) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if (cookie != 0) {
if (*cookie != 0) {
fprintf(stderr,"<- B_ERROR (no more inputs)\n");
return B_ERROR;
}
*cookie = 1;
}
*out_input = input;
return B_OK;
}
void MediaWriter::DisposeInputCookie(
int32 cookie)
{
fprintf(stderr,"MediaWriter::DisposeInputCookie\n");
return;
}
void MediaWriter::BufferReceived(
BBuffer * buffer)
{
fprintf(stderr,"MediaWriter::BufferReceived\n");
switch (buffer->Header()->type) {
case B_MEDIA_PARAMETERS:
{
status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
if (status != B_OK) {
fprintf(stderr,"ApplyParameterData in MediaWriter::BufferReceived failed\n");
}
buffer->Recycle();
}
break;
case B_MEDIA_MULTISTREAM:
if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) {
fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MediaWriter::BufferReceived\n");
buffer->Recycle();
} else {
media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
status_t status = EventQueue()->AddEvent(event);
if (status != B_OK) {
fprintf(stderr,"EventQueue()->AddEvent(event) in MediaWriter::BufferReceived failed\n");
buffer->Recycle();
}
}
break;
default:
fprintf(stderr,"unexpected buffer type in MediaWriter::BufferReceived\n");
buffer->Recycle();
break;
}
}
void MediaWriter::ProducerDataStatus(
const media_destination & for_whom,
int32 status,
bigtime_t at_performance_time)
{
fprintf(stderr,"MediaWriter::ProducerDataStatus\n");
if (input.destination != for_whom) {
fprintf(stderr,"invalid destination received in MediaWriter::ProducerDataStatus\n");
return;
}
media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
&input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
EventQueue()->AddEvent(event);
}
status_t MediaWriter::GetLatencyFor(
const media_destination & for_whom,
bigtime_t * out_latency,
media_node_id * out_timesource)
{
fprintf(stderr,"MediaWriter::GetLatencyFor\n");
if ((out_latency == 0) || (out_timesource == 0)) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if (input.destination != for_whom) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
*out_latency = EventLatency();
*out_timesource = TimeSource()->ID();
return B_OK;
}
status_t MediaWriter::Connected(
const media_source & producer,
const media_destination & where,
const media_format & with_format,
media_input * out_input)
{
fprintf(stderr,"MediaWriter::Connected\n");
if (out_input == 0) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if (input.destination != where) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
if (fBufferGroup != 0) {
BBufferGroup * group = fBufferGroup;
fBufferGroup = 0;
delete group;
}
if (GetCurrentFile() != 0) {
bigtime_t start, end;
uint8 * data = new uint8[input.format.u.multistream.max_chunk_size];
ssize_t bytesWritten = 0;
{
start = TimeSource()->RealTime();
bytesWritten = GetCurrentFile()->Write(data,input.format.u.multistream.max_chunk_size);
end = TimeSource()->RealTime();
}
delete[] data;
GetCurrentFile()->Seek(-bytesWritten,SEEK_CUR);
fInternalLatency = end - start;
fprintf(stderr," internal latency from disk write = %lld\n",fInternalLatency);
} else {
fInternalLatency = 500;
fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency);
}
SetEventLatency(fInternalLatency);
input.source = producer;
input.format = with_format;
*out_input = input;
return B_OK;
}
void MediaWriter::Disconnected(
const media_source & producer,
const media_destination & where)
{
fprintf(stderr,"MediaWriter::Disconnected\n");
if (input.destination != where) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return;
}
if (input.source != producer) {
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
return;
}
input.source = media_source::null;
GetFormat(&input.format);
if (fBufferGroup != 0) {
BBufferGroup * group = fBufferGroup;
fBufferGroup = 0;
delete group;
}
}
status_t MediaWriter::FormatChanged(
const media_source & producer,
const media_destination & consumer,
int32 change_tag,
const media_format & format)
{
fprintf(stderr,"MediaWriter::FormatChanged\n");
if (input.source != producer) {
return B_MEDIA_BAD_SOURCE;
}
if (input.destination != consumer) {
return B_MEDIA_BAD_DESTINATION;
}
input.format = format;
return B_OK;
}
status_t MediaWriter::SeekTagRequested(
const media_destination & destination,
bigtime_t in_target_time,
uint32 in_flags,
media_seek_tag * out_seek_tag,
bigtime_t * out_tagged_time,
uint32 * out_flags)
{
fprintf(stderr,"MediaWriter::SeekTagRequested\n");
return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags,
out_seek_tag,out_tagged_time,out_flags);
}
status_t MediaWriter::HandleBuffer(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
fprintf(stderr,"MediaWriter::HandleBuffer\n");
BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
if (buffer == 0) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if (buffer->Header()->destination != input.destination.id) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
WriteFileBuffer(buffer);
buffer->Recycle();
return B_OK;
}
status_t MediaWriter::HandleDataStatus(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvents)
{
fprintf(stderr,"MediaWriter::HandleDataStatus");
return B_OK;
}
void MediaWriter::GetFlavor(flavor_info * outInfo, int32 id)
{
fprintf(stderr,"MediaWriter::GetFlavor\n");
if (outInfo == 0) {
return;
}
AbstractFileInterfaceNode::GetFlavor(outInfo,id);
strcpy(outInfo->name, "Media Writer");
strcpy(outInfo->info,
"The Haiku Media Writer consumes a multistream and writes a file.");
outInfo->kinds |= B_BUFFER_CONSUMER;
outInfo->in_format_count = 1;
media_format * formats = new media_format[outInfo->in_format_count];
GetFormat(&formats[0]);
outInfo->in_formats = formats;
return;
}
void MediaWriter::GetFormat(media_format * outFormat)
{
fprintf(stderr,"MediaWriter::GetFormat\n");
if (outFormat == 0) {
return;
}
AbstractFileInterfaceNode::GetFormat(outFormat);
return;
}
void MediaWriter::GetFileFormat(media_file_format * outFileFormat)
{
fprintf(stderr,"MediaWriter::GetFileFormat\n");
if (outFileFormat == 0) {
return;
}
AbstractFileInterfaceNode::GetFileFormat(outFileFormat);
outFileFormat->capabilities |= media_file_format::B_WRITABLE;
return;
}
status_t MediaWriter::WriteFileBuffer(
BBuffer * buffer)
{
fprintf(stderr,"MediaWriter::WriteFileBuffer\n");
if (GetCurrentFile() == 0) {
fprintf(stderr,"<- B_NO_INIT\n");
return B_NO_INIT;
}
fprintf(stderr," writing %" B_PRId32 " bytes at %lld\n",
buffer->SizeUsed(),GetCurrentFile()->Position());
ssize_t bytesWriten = GetCurrentFile()->Write(buffer->Data(),buffer->SizeUsed());
if (bytesWriten < 0) {
fprintf(stderr,"<- B_IO_ERROR\n");
return B_IO_ERROR;
}
return B_OK;
}
status_t MediaWriter::_Reserved_MediaWriter_0(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_1(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_2(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_3(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_4(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_5(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_6(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_7(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_8(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_9(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_10(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_11(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_12(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_13(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_14(void *) { return B_ERROR; }
status_t MediaWriter::_Reserved_MediaWriter_15(void *) { return B_ERROR; }