diff --git a/src/add-ons/media/media-add-ons/Jamfile b/src/add-ons/media/media-add-ons/Jamfile index d03a147f6a..b983705b98 100644 --- a/src/add-ons/media/media-add-ons/Jamfile +++ b/src/add-ons/media/media-add-ons/Jamfile @@ -6,4 +6,5 @@ SubInclude OBOS_TOP src add-ons media media-add-ons writer ; SubInclude OBOS_TOP src add-ons media media-add-ons legacy ; SubInclude OBOS_TOP src add-ons media media-add-ons mixer ; SubInclude OBOS_TOP src add-ons media media-add-ons multi_audio ; +SubInclude OBOS_TOP src add-ons media media-add-ons video_producer_demo ; diff --git a/src/add-ons/media/media-add-ons/video_producer_demo/AddOn.cpp b/src/add-ons/media/media-add-ons/video_producer_demo/AddOn.cpp new file mode 100644 index 0000000000..cae2ddf7ba --- /dev/null +++ b/src/add-ons/media/media-add-ons/video_producer_demo/AddOn.cpp @@ -0,0 +1,111 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ +#include +#include +#include +#include +#include + +#include "AddOn.h" +#include "Producer.h" + +MediaAddOn::MediaAddOn(image_id imid) + : BMediaAddOn(imid) +{ + /* Customize these parameters to match those of your node */ + fFlavorInfo.name = "VideoProducer"; + fFlavorInfo.info = "VideoProducer"; + fFlavorInfo.kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT; + fFlavorInfo.flavor_flags = 0; + fFlavorInfo.internal_id = 0; + fFlavorInfo.possible_count = 1; + fFlavorInfo.in_format_count = 0; + fFlavorInfo.in_format_flags = 0; + fFlavorInfo.in_formats = NULL; + fFlavorInfo.out_format_count = 1; + fFlavorInfo.out_format_flags = 0; + fMediaFormat.type = B_MEDIA_RAW_VIDEO; + fMediaFormat.u.raw_video = media_raw_video_format::wildcard; + fMediaFormat.u.raw_video.interlace = 1; + fMediaFormat.u.raw_video.display.format = B_RGB32; + fFlavorInfo.out_formats = &fMediaFormat; + + fInitStatus = B_OK; +} + +MediaAddOn::~MediaAddOn() +{ +} + + +status_t +MediaAddOn::InitCheck(const char **out_failure_text) +{ + if (fInitStatus < B_OK) { + *out_failure_text = "Unknown error"; + return fInitStatus; + } + + return B_OK; +} + +int32 +MediaAddOn::CountFlavors() +{ + if (fInitStatus < B_OK) + return fInitStatus; + + /* This addon only supports a single flavor, as defined in the + * constructor */ + return 1; +} + +/* + * The pointer to the flavor received only needs to be valid between + * successive calls to BMediaAddOn::GetFlavorAt(). + */ +status_t +MediaAddOn::GetFlavorAt(int32 n, const flavor_info **out_info) +{ + if (fInitStatus < B_OK) + return fInitStatus; + + if (n != 0) + return B_BAD_INDEX; + + /* Return the flavor defined in the constructor */ + *out_info = &fFlavorInfo; + return B_OK; +} + +BMediaNode * +MediaAddOn::InstantiateNodeFor( + const flavor_info *info, BMessage *config, status_t *out_error) +{ + VideoProducer *node; + + if (fInitStatus < B_OK) + return NULL; + + if (info->internal_id != fFlavorInfo.internal_id) + return NULL; + + /* At most one instance of the node should be instantiated at any given + * time. The locking for this restriction may be found in the VideoProducer + * class. */ + node = new VideoProducer(this, fFlavorInfo.name, fFlavorInfo.internal_id); + if (node && (node->InitCheck() < B_OK)) { + delete node; + node = NULL; + } + + return node; +} + +BMediaAddOn * +make_media_addon(image_id imid) +{ + return new MediaAddOn(imid); +} diff --git a/src/add-ons/media/media-add-ons/video_producer_demo/AddOn.h b/src/add-ons/media/media-add-ons/video_producer_demo/AddOn.h new file mode 100644 index 0000000000..1a0c63208f --- /dev/null +++ b/src/add-ons/media/media-add-ons/video_producer_demo/AddOn.h @@ -0,0 +1,43 @@ +#ifndef _VIDEO_ADDON_H +#define _VIDEO_ADDON_H + +#include + +#define TOUCH(x) ((void)(x)) + +extern "C" _EXPORT BMediaAddOn *make_media_addon(image_id you); + +class MediaAddOn : public BMediaAddOn +{ +public: + MediaAddOn(image_id imid); + virtual ~MediaAddOn(); + + virtual status_t InitCheck(const char **out_failure_text); + + virtual int32 CountFlavors(); + virtual status_t GetFlavorAt(int32 n, const flavor_info ** out_info); + virtual BMediaNode *InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error); + + virtual status_t GetConfigurationFor(BMediaNode *node, BMessage *message) + { TOUCH(node); TOUCH(message); return B_OK; } + virtual status_t SaveConfigInfo(BMediaNode *node, BMessage *message) + { TOUCH(node); TOUCH(message); return B_OK; } + + virtual bool WantsAutoStart() { return false; } + virtual status_t AutoStart(int in_count, BMediaNode **out_node, + int32 *out_internal_id, bool *out_has_more) + { TOUCH(in_count); TOUCH(out_node); + TOUCH(out_internal_id); TOUCH(out_has_more); + return B_ERROR; } + +private: + status_t fInitStatus; + flavor_info fFlavorInfo; + media_format fMediaFormat; +}; + +#endif diff --git a/src/add-ons/media/media-add-ons/video_producer_demo/Jamfile b/src/add-ons/media/media-add-ons/video_producer_demo/Jamfile new file mode 100644 index 0000000000..1fb69b7dcb --- /dev/null +++ b/src/add-ons/media/media-add-ons/video_producer_demo/Jamfile @@ -0,0 +1,8 @@ +SubDir OBOS_TOP src add-ons media media-add-ons video_producer_demo ; + +Addon video_producer_demo.media_addon : media : + AddOn.cpp + Producer.cpp +; + +LinkSharedOSLibs video_producer_demo.media_addon : be media ; diff --git a/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp b/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp new file mode 100644 index 0000000000..dc723d3ae4 --- /dev/null +++ b/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp @@ -0,0 +1,749 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define TOUCH(x) ((void)(x)) + +#define PRINTF(a,b) \ + do { \ + if (a < 2) { \ + printf("VideoProducer::"); \ + printf b; \ + } \ + } while (0) + +#include "Producer.h" + +#define FIELD_RATE 30.f + +int32 VideoProducer::fInstances = 0; + +VideoProducer::VideoProducer( + BMediaAddOn *addon, const char *name, int32 internal_id) + : BMediaNode(name), + BMediaEventLooper(), + BBufferProducer(B_MEDIA_RAW_VIDEO), + BControllable() +{ + status_t err; + + fInitStatus = B_NO_INIT; + + /* Only allow one instance of the node to exist at any time */ + if (atomic_add(&fInstances, 1) != 0) + return; + + fInternalID = internal_id; + fAddOn = addon; + + fBufferGroup = NULL; + + fThread = -1; + fFrameSync = -1; + fProcessingLatency = 0LL; + + fRunning = false; + fConnected = false; + fEnabled = false; + + fOutput.destination = media_destination::null; + + AddNodeKind(B_PHYSICAL_INPUT); + + fInitStatus = B_OK; + return; +} + +VideoProducer::~VideoProducer() +{ + if (fInitStatus == B_OK) { + /* Clean up after ourselves, in case the application didn't make us + * do so. */ + if (fConnected) + Disconnect(fOutput.source, fOutput.destination); + if (fRunning) + HandleStop(); + } + + atomic_add(&fInstances, -1); +} + +/* BMediaNode */ + +port_id +VideoProducer::ControlPort() const +{ + return BMediaNode::ControlPort(); +} + +BMediaAddOn * +VideoProducer::AddOn(int32 *internal_id) const +{ + if (internal_id) + *internal_id = fInternalID; + return fAddOn; +} + +status_t +VideoProducer::HandleMessage(int32 message, const void *data, size_t size) +{ + return B_ERROR; +} + +void +VideoProducer::Preroll() +{ + /* This hook may be called before the node is started to give the hardware + * a chance to start. */ +} + +void +VideoProducer::SetTimeSource(BTimeSource *time_source) +{ + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +status_t +VideoProducer::RequestCompleted(const media_request_info &info) +{ + return BMediaNode::RequestCompleted(info); +} + +/* BMediaEventLooper */ + +void +VideoProducer::NodeRegistered() +{ + if (fInitStatus != B_OK) { + ReportError(B_NODE_IN_DISTRESS); + return; + } + + /* Set up the parameter web */ + BParameterWeb *web = new BParameterWeb(); + BParameterGroup *main = web->MakeGroup(Name()); + BDiscreteParameter *state = main->MakeDiscreteParameter( + P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue"); + + fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000); + fLastColorChange = system_time(); + + /* After this call, the BControllable owns the BParameterWeb object and + * will delete it for you */ + SetParameterWeb(web); + + fOutput.node = Node(); + fOutput.source.port = ControlPort(); + fOutput.source.id = 0; + fOutput.destination = media_destination::null; + strcpy(fOutput.name, Name()); + + /* Tailor these for the output of your device */ + fOutput.format.type = B_MEDIA_RAW_VIDEO; + fOutput.format.u.raw_video = media_raw_video_format::wildcard; + fOutput.format.u.raw_video.interlace = 1; + fOutput.format.u.raw_video.display.format = B_RGB32; + + /* Start the BMediaEventLooper control loop running */ + Run(); +} + +void +VideoProducer::Start(bigtime_t performance_time) +{ + BMediaEventLooper::Start(performance_time); +} + +void +VideoProducer::Stop(bigtime_t performance_time, bool immediate) +{ + BMediaEventLooper::Stop(performance_time, immediate); +} + +void +VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time) +{ + BMediaEventLooper::Seek(media_time, performance_time); +} + +void +VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) +{ + BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); +} + +status_t +VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie) +{ + return BMediaEventLooper::AddTimer(at_performance_time, cookie); +} + +void +VideoProducer::SetRunMode(run_mode mode) +{ + BMediaEventLooper::SetRunMode(mode); +} + +void +VideoProducer::HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent) +{ + TOUCH(lateness); TOUCH(realTimeEvent); + + switch(event->type) + { + case BTimedEventQueue::B_START: + HandleStart(event->event_time); + break; + case BTimedEventQueue::B_STOP: + HandleStop(); + break; + case BTimedEventQueue::B_WARP: + HandleTimeWarp(event->bigdata); + break; + case BTimedEventQueue::B_SEEK: + HandleSeek(event->bigdata); + break; + case BTimedEventQueue::B_HANDLE_BUFFER: + case BTimedEventQueue::B_DATA_STATUS: + case BTimedEventQueue::B_PARAMETER: + default: + PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type)); + break; + } +} + +void +VideoProducer::CleanUpEvent(const media_timed_event *event) +{ + BMediaEventLooper::CleanUpEvent(event); +} + +bigtime_t +VideoProducer::OfflineTime() +{ + return BMediaEventLooper::OfflineTime(); +} + +void +VideoProducer::ControlLoop() +{ + BMediaEventLooper::ControlLoop(); +} + +status_t +VideoProducer::DeleteHook(BMediaNode * node) +{ + return BMediaEventLooper::DeleteHook(node); +} + +/* BBufferProducer */ + +status_t +VideoProducer::FormatSuggestionRequested( + media_type type, int32 quality, media_format *format) +{ + if (type != B_MEDIA_ENCODED_VIDEO) + return B_MEDIA_BAD_FORMAT; + + TOUCH(quality); + + *format = fOutput.format; + return B_OK; +} + +status_t +VideoProducer::FormatProposal(const media_source &output, media_format *format) +{ + status_t err; + + if (!format) + return B_BAD_VALUE; + + if (output != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + err = format_is_compatible(*format, fOutput.format) ? + B_OK : B_MEDIA_BAD_FORMAT; + *format = fOutput.format; + return err; + +} + +status_t +VideoProducer::FormatChangeRequested(const media_source &source, + const media_destination &destination, media_format *io_format, + int32 *_deprecated_) +{ + TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_); + if (source != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + return B_ERROR; +} + +status_t +VideoProducer::GetNextOutput(int32 *cookie, media_output *out_output) +{ + if (!out_output) + return B_BAD_VALUE; + + if ((*cookie) != 0) + return B_BAD_INDEX; + + *out_output = fOutput; + (*cookie)++; + return B_OK; +} + +status_t +VideoProducer::DisposeOutputCookie(int32 cookie) +{ + TOUCH(cookie); + + return B_OK; +} + +status_t +VideoProducer::SetBufferGroup(const media_source &for_source, + BBufferGroup *group) +{ + TOUCH(for_source); TOUCH(group); + + return B_ERROR; +} + +status_t +VideoProducer::VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, int32 *_deprecated_) +{ + TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data); + TOUCH(display); TOUCH(_deprecated_); + + return B_ERROR; +} + +status_t +VideoProducer::GetLatency(bigtime_t *out_latency) +{ + *out_latency = EventLatency() + SchedulingLatency(); + return B_OK; +} + +status_t +VideoProducer::PrepareToConnect(const media_source &source, + const media_destination &destination, media_format *format, + media_source *out_source, char *out_name) +{ + status_t err; + + PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \ + format->u.raw_video.display.line_width, \ + format->u.raw_video.display.line_count)); + + if (fConnected) { + PRINTF(0, ("PrepareToConnect: Already connected\n")); + return EALREADY; + } + + if (source != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + if (fOutput.destination != media_destination::null) + return B_MEDIA_ALREADY_CONNECTED; + + /* The format parameter comes in with the suggested format, and may be + * specialized as desired by the node */ + if (!format_is_compatible(*format, fOutput.format)) { + *format = fOutput.format; + return B_MEDIA_BAD_FORMAT; + } + + if (format->u.raw_video.display.line_width == 0) + format->u.raw_video.display.line_width = 320; + if (format->u.raw_video.display.line_count == 0) + format->u.raw_video.display.line_count = 240; + if (format->u.raw_video.field_rate == 0) + format->u.raw_video.field_rate = 29.97f; + + *out_source = fOutput.source; + strcpy(out_name, fOutput.name); + + fOutput.destination = destination; + + return B_OK; +} + +void +VideoProducer::Connect(status_t error, const media_source &source, + const media_destination &destination, const media_format &format, + char *io_name) +{ + PRINTF(1, ("Connect() %ldx%ld\n", \ + format.u.raw_video.display.line_width, \ + format.u.raw_video.display.line_count)); + + if (fConnected) { + PRINTF(0, ("Connect: Already connected\n")); + return; + } + + if ( (source != fOutput.source) || (error < B_OK) || + !const_cast(&format)->Matches(&fOutput.format)) { + PRINTF(1, ("Connect: Connect error\n")); + return; + } + + fOutput.destination = destination; + strcpy(io_name, fOutput.name); + + if (fOutput.format.u.raw_video.field_rate != 0.0f) { + fPerformanceTimeBase = fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fOutput.format.u.raw_video.field_rate)); + fFrameBase = fFrame; + } + + fConnectedFormat = format.u.raw_video; + + /* get the latency */ + bigtime_t latency = 0; + media_node_id tsID = 0; + FindLatencyFor(fOutput.destination, &latency, &tsID); + #define NODE_LATENCY 1000 + SetEventLatency(latency + NODE_LATENCY); + + uint32 *buffer, *p, f = 3; + p = buffer = (uint32 *)malloc(4 * fConnectedFormat.display.line_count * + fConnectedFormat.display.line_width); + if (!buffer) { + PRINTF(0, ("Connect: Out of memory\n")); + return; + } + bigtime_t now = system_time(); + for (int y=0;yInitCheck() < B_OK) { + delete fBufferGroup; + fBufferGroup = NULL; + return; + } + + fConnected = true; + fEnabled = true; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::Disconnect(const media_source &source, + const media_destination &destination) +{ + PRINTF(1, ("Disconnect()\n")); + + if (!fConnected) { + PRINTF(0, ("Disconnect: Not connected\n")); + return; + } + + if ((source != fOutput.source) || (destination != fOutput.destination)) { + PRINTF(0, ("Disconnect: Bad source and/or destination\n")); + return; + } + + fEnabled = false; + fOutput.destination = media_destination::null; + + fLock.Lock(); + delete fBufferGroup; + fBufferGroup = NULL; + fLock.Unlock(); + + fConnected = false; +} + +void +VideoProducer::LateNoticeReceived(const media_source &source, + bigtime_t how_much, bigtime_t performance_time) +{ + TOUCH(source); TOUCH(how_much); TOUCH(performance_time); +} + +void +VideoProducer::EnableOutput(const media_source &source, bool enabled, + int32 *_deprecated_) +{ + TOUCH(_deprecated_); + + if (source != fOutput.source) + return; + + fEnabled = enabled; +} + +status_t +VideoProducer::SetPlayRate(int32 numer, int32 denom) +{ + TOUCH(numer); TOUCH(denom); + + return B_ERROR; +} + +void +VideoProducer::AdditionalBufferRequested(const media_source &source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag *prev_tag) +{ + TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag); +} + +void +VideoProducer::LatencyChanged(const media_source &source, + const media_destination &destination, bigtime_t new_latency, + uint32 flags) +{ + TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags); +} + +/* BControllable */ + +status_t +VideoProducer::GetParameterValue( + int32 id, bigtime_t *last_change, void *value, size_t *size) +{ + if (id != P_COLOR) + return B_BAD_VALUE; + + *last_change = fLastColorChange; + *size = sizeof(uint32); + *((uint32 *)value) = fColor; + + return B_OK; +} + +void +VideoProducer::SetParameterValue( + int32 id, bigtime_t when, const void *value, size_t size) +{ + if ((id != P_COLOR) || !value || (size != sizeof(uint32))) + return; + + if (*(int32 *)value == fColor) + return; + + fColor = *(uint32 *)value; + fLastColorChange = when; + + BroadcastNewParameterValue( + fLastColorChange, P_COLOR, &fColor, sizeof(fColor)); +} + +status_t +VideoProducer::StartControlPanel(BMessenger *out_messenger) +{ + return BControllable::StartControlPanel(out_messenger); +} + +/* VideoProducer */ + +void +VideoProducer::HandleStart(bigtime_t performance_time) +{ + /* Start producing frames, even if the output hasn't been connected yet. */ + + PRINTF(1, ("HandleStart(%Ld)\n", performance_time)); + + if (fRunning) { + PRINTF(-1, ("HandleStart: Node already started\n")); + return; + } + + fFrame = 0; + fFrameBase = 0; + fPerformanceTimeBase = performance_time; + + fFrameSync = create_sem(0, "frame synchronization"); + if (fFrameSync < B_OK) + goto err1; + + fThread = spawn_thread(_frame_generator_, "frame generator", + B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + goto err2; + + resume_thread(fThread); + + fRunning = true; + return; + +err2: + delete_sem(fFrameSync); +err1: + return; +} + +void +VideoProducer::HandleStop(void) +{ + PRINTF(1, ("HandleStop()\n")); + + if (!fRunning) { + PRINTF(-1, ("HandleStop: Node isn't running\n")); + return; + } + + delete_sem(fFrameSync); + wait_for_thread(fThread, &fThread); + + fRunning = false; +} + +void +VideoProducer::HandleTimeWarp(bigtime_t performance_time) +{ + fPerformanceTimeBase = performance_time; + fFrameBase = fFrame; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::HandleSeek(bigtime_t performance_time) +{ + fPerformanceTimeBase = performance_time; + fFrameBase = fFrame; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +/* The following functions form the thread that generates frames. You should + * replace this with the code that interfaces to your hardware. */ +int32 +VideoProducer::FrameGenerator() +{ + bigtime_t wait_until = system_time(); + + while (1) { + status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, + wait_until); + + /* The only acceptable responses are B_OK and B_TIMED_OUT. Everything + * else means the thread should quit. Deleting the semaphore, as in + * VideoProducer::HandleStop(), will trigger this behavior. */ + if ((err != B_OK) && (err != B_TIMED_OUT)) + break; + + fFrame++; + + /* Recalculate the time until the thread should wake up to begin + * processing the next frame. Subtract fProcessingLatency so that + * the frame is sent in time. */ + wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase, 0) + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fConnectedFormat.field_rate)) - + fProcessingLatency; + + /* Drop frame if it's at least a frame late */ + if (wait_until < system_time()) + continue; + + /* If the semaphore was acquired successfully, it means something + * changed the timing information (see VideoProducer::Connect()) and + * so the thread should go back to sleep until the newly-calculated + * wait_until time. */ + if (err == B_OK) + continue; + + /* Send buffers only if the node is running and the output has been + * enabled */ + if (!fRunning || !fEnabled) + continue; + + BAutolock _(fLock); + + /* Fetch a buffer from the buffer group */ + BBuffer *buffer = fBufferGroup->RequestBuffer( + 4 * fConnectedFormat.display.line_width * + fConnectedFormat.display.line_count, 0LL); + if (!buffer) + continue; + + /* Fill out the details about this buffer. */ + media_header *h = buffer->Header(); + h->type = B_MEDIA_RAW_VIDEO; + h->time_source = TimeSource()->ID(); + h->size_used = 4 * fConnectedFormat.display.line_width * + fConnectedFormat.display.line_count; + /* For a buffer originating from a device, you might want to calculate + * this based on the PerformanceTimeFor the time your buffer arrived at + * the hardware (plus any applicable adjustments). */ + h->start_time = fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fConnectedFormat.field_rate)); + h->file_pos = 0; + h->orig_size = 0; + h->data_offset = 0; + h->u.raw_video.field_gamma = 1.0; + h->u.raw_video.field_sequence = fFrame; + h->u.raw_video.field_number = 0; + h->u.raw_video.pulldown_number = 0; + h->u.raw_video.first_active_line = 1; + h->u.raw_video.line_count = fConnectedFormat.display.line_count; + + /* Fill in a pattern */ + uint32 *p = (uint32 *)buffer->Data(); + for (int y=0;yRecycle(); + } + } + + return B_OK; +} + +int32 +VideoProducer::_frame_generator_(void *data) +{ + return ((VideoProducer *)data)->FrameGenerator(); +} diff --git a/src/add-ons/media/media-add-ons/video_producer_demo/Producer.h b/src/add-ons/media/media-add-ons/video_producer_demo/Producer.h new file mode 100644 index 0000000000..b8fc214da3 --- /dev/null +++ b/src/add-ons/media/media-add-ons/video_producer_demo/Producer.h @@ -0,0 +1,138 @@ +#ifndef _VIDEO_PRODUCER_H +#define _VIDEO_PRODUCER_H + +#include +#include +#include +#include +#include +#include +#include + +class VideoProducer : + public virtual BMediaEventLooper, + public virtual BBufferProducer, + public virtual BControllable +{ +public: + VideoProducer(BMediaAddOn *addon, + const char *name, int32 internal_id); +virtual ~VideoProducer(); + +virtual status_t InitCheck() const { return fInitStatus; } + +/* BMediaNode */ +public: +virtual port_id ControlPort() const; +virtual BMediaAddOn *AddOn(int32 * internal_id) const; +virtual status_t HandleMessage(int32 message, const void *data, + size_t size); +protected: +virtual void Preroll(); +virtual void SetTimeSource(BTimeSource * time_source); +virtual status_t RequestCompleted(const media_request_info & info); + +/* BMediaEventLooper */ +protected: +virtual void NodeRegistered(); +virtual void Start(bigtime_t performance_time); +virtual void Stop(bigtime_t performance_time, bool immediate); +virtual void Seek(bigtime_t media_time, bigtime_t performance_time); +virtual void TimeWarp(bigtime_t at_real_time, + bigtime_t to_performance_time); +virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie); +virtual void SetRunMode(run_mode mode); +virtual void HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent = false); +virtual void CleanUpEvent(const media_timed_event *event); +virtual bigtime_t OfflineTime(); +virtual void ControlLoop(); +virtual status_t DeleteHook(BMediaNode * node); + +/* BBufferProducer */ +protected: +virtual status_t FormatSuggestionRequested(media_type type, int32 quality, + media_format * format); +virtual status_t FormatProposal(const media_source &output, + media_format *format); +virtual status_t FormatChangeRequested(const media_source &source, + const media_destination &destination, + media_format *io_format, int32 *_deprecated_); +virtual status_t GetNextOutput(int32 * cookie, media_output * out_output); +virtual status_t DisposeOutputCookie(int32 cookie); +virtual status_t SetBufferGroup(const media_source &for_source, + BBufferGroup * group); +virtual status_t VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, + int32 * _deprecated_); +virtual status_t GetLatency(bigtime_t * out_latency); +virtual status_t PrepareToConnect(const media_source &what, + const media_destination &where, + media_format *format, + media_source *out_source, char *out_name); +virtual void Connect(status_t error, const media_source &source, + const media_destination &destination, + const media_format & format, char *io_name); +virtual void Disconnect(const media_source & what, + const media_destination & where); +virtual void LateNoticeReceived(const media_source & what, + bigtime_t how_much, bigtime_t performance_time); +virtual void EnableOutput(const media_source & what, bool enabled, + int32 * _deprecated_); +virtual status_t SetPlayRate(int32 numer,int32 denom); +virtual void AdditionalBufferRequested(const media_source & source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag * prev_tag); +virtual void LatencyChanged(const media_source & source, + const media_destination & destination, + bigtime_t new_latency, uint32 flags); + +/* BControllable */ +protected: +virtual status_t GetParameterValue(int32 id, bigtime_t *last_change, + void *value, size_t *size); +virtual void SetParameterValue(int32 id, bigtime_t when, + const void *value, size_t size); +virtual status_t StartControlPanel(BMessenger *out_messenger); + +/* state */ +private: + void HandleStart(bigtime_t performance_time); + void HandleStop(); + void HandleTimeWarp(bigtime_t performance_time); + void HandleSeek(bigtime_t performance_time); + +static int32 fInstances; + + status_t fInitStatus; + + int32 fInternalID; + BMediaAddOn *fAddOn; + + BLocker fLock; + BBufferGroup *fBufferGroup; + + thread_id fThread; + sem_id fFrameSync; +static int32 _frame_generator_(void *data); + int32 FrameGenerator(); + + /* The remaining variables should be declared volatile, but they + * are not here to improve the legibility of the sample code. */ + uint32 fFrame; + uint32 fFrameBase; + bigtime_t fPerformanceTimeBase; + bigtime_t fProcessingLatency; + media_output fOutput; + media_raw_video_format fConnectedFormat; + bool fRunning; + bool fConnected; + bool fEnabled; + + enum { P_COLOR }; + uint32 fColor; + bigtime_t fLastColorChange; +}; + +#endif