1/* 2* Copyright (C) 2009-2010 David McPaul 3* 4* All rights reserved. Distributed under the terms of the MIT License. 5*/ 6 7#ifndef _VIDEO_MIXER_NODE_H 8#define _VIDEO_MIXER_NODE_H 9 10#include <Buffer.h> 11#include <BufferConsumer.h> 12#include <BufferGroup.h> 13#include <BufferProducer.h> 14#include <MediaAddOn.h> 15#include <MediaDefs.h> 16#include <MediaEventLooper.h> 17#include <MediaNode.h> 18#include <TimeSource.h> 19 20#include <vector> 21 22#include "BufferMixer.h" 23 24class VideoMixerNode : 25 public BBufferConsumer, 26 public BBufferProducer, 27 public BMediaEventLooper 28{ 29protected: 30virtual ~VideoMixerNode(void); 31 32public: 33 34explicit VideoMixerNode( 35 const flavor_info * info = 0, 36 BMessage *config = 0, 37 BMediaAddOn *addOn = 0); 38 39virtual status_t InitCheck(void) const; 40 41// see BMediaAddOn::GetConfigurationFor 42virtual status_t GetConfigurationFor( 43 BMessage *into_message); 44 45public: 46// /* this port is what a media node listens to for commands */ 47// virtual port_id ControlPort(void) const; 48 49virtual BMediaAddOn* AddOn( 50 int32 *internal_id) const; /* Who instantiated you -- or NULL for app class */ 51 52protected: 53 /* These don't return errors; instead, they use the global error condition reporter. */ 54 /* A node is required to have a queue of at least one pending command (plus TimeWarp) */ 55 /* and is recommended to allow for at least one pending command of each type. */ 56 /* Allowing an arbitrary number of outstanding commands might be nice, but apps */ 57 /* cannot depend on that happening. */ 58virtual void Start( 59 bigtime_t performance_time); 60virtual void Stop( 61 bigtime_t performance_time, 62 bool immediate); 63virtual void Seek( 64 bigtime_t media_time, 65 bigtime_t performance_time); 66virtual void SetRunMode( 67 run_mode mode); 68virtual void TimeWarp( 69 bigtime_t at_real_time, 70 bigtime_t to_performance_time); 71virtual void Preroll(void); 72virtual void SetTimeSource(BTimeSource *time_source); 73 74public: 75virtual status_t HandleMessage( 76 int32 message, 77 const void *data, 78 size_t size); 79 80protected: 81 /* Called when requests have completed, or failed. */ 82virtual status_t RequestCompleted( /* reserved 0 */ 83 const media_request_info &info); 84 85protected: 86virtual status_t DeleteHook(BMediaNode *node); /* reserved 1 */ 87 88virtual void NodeRegistered(void); /* reserved 2 */ 89 90public: 91 92 /* fill out your attributes in the provided array, returning however many you have. */ 93virtual status_t GetNodeAttributes( /* reserved 3 */ 94 media_node_attribute *outAttributes, 95 size_t inMaxCount); 96 97virtual status_t AddTimer( 98 bigtime_t at_performance_time, 99 int32 cookie); 100 101 /* Someone, probably the producer, is asking you about this format. Give */ 102 /* your honest opinion, possibly modifying *format. Do not ask upstream */ 103 /* producer about the format, since he's synchronously waiting for your */ 104 /* reply. */ 105virtual status_t AcceptFormat( 106 const media_destination &dest, 107 media_format *format); 108virtual status_t GetNextInput( 109 int32 * cookie, 110 media_input *out_input); 111virtual void DisposeInputCookie(int32 cookie); 112virtual void BufferReceived(BBuffer *buffer); 113virtual void ProducerDataStatus( 114 const media_destination &for_whom, 115 int32 status, 116 bigtime_t at_performance_time); 117virtual status_t GetLatencyFor( 118 const media_destination &for_whom, 119 bigtime_t *out_latency, 120 media_node_id *out_timesource); 121virtual status_t Connected( 122 const media_source &producer, /* here's a good place to request buffer group usage */ 123 const media_destination &where, 124 const media_format &with_format, 125 media_input *out_input); 126virtual void Disconnected( 127 const media_source &producer, 128 const media_destination &where); 129 /* The notification comes from the upstream producer, so he's already cool with */ 130 /* the format; you should not ask him about it in here. */ 131virtual status_t FormatChanged( 132 const media_source &producer, 133 const media_destination &consumer, 134 int32 change_tag, 135 const media_format &format); 136 137 /* Given a performance time of some previous buffer, retrieve the remembered tag */ 138 /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ 139 /* idea being that flags can be added later, and the understood flags returned in */ 140 /* *out_flags. */ 141virtual status_t SeekTagRequested( 142 const media_destination &destination, 143 bigtime_t in_target_time, 144 uint32 in_flags, 145 media_seek_tag *out_seek_tag, 146 bigtime_t *out_tagged_time, 147 uint32 *out_flags); 148 149 150protected: 151 /* functionality of BBufferProducer */ 152virtual status_t FormatSuggestionRequested( 153 media_type type, 154 int32 quality, 155 media_format *format); 156virtual status_t FormatProposal( 157 const media_source &output, 158 media_format *format); 159 /* If the format isn't good, put a good format into *io_format and return error */ 160 /* If format has wildcard, specialize to what you can do (and change). */ 161 /* If you can change the format, return OK. */ 162 /* The request comes from your destination sychronously, so you cannot ask it */ 163 /* whether it likes it -- you should assume it will since it asked. */ 164virtual status_t FormatChangeRequested( 165 const media_source &source, 166 const media_destination &destination, 167 media_format *io_format, 168 int32 *_deprecated_); 169virtual status_t GetNextOutput( /* cookie starts as 0 */ 170 int32 *cookie, 171 media_output *out_output); 172virtual status_t DisposeOutputCookie( 173 int32 cookie); 174 /* In this function, you should either pass on the group to your upstream guy, */ 175 /* or delete your current group and hang on to this group. Deleting the previous */ 176 /* group (unless you passed it on with the reclaim flag set to false) is very */ 177 /* important, else you will 1) leak memory and 2) block someone who may want */ 178 /* to reclaim the buffers living in that group. */ 179virtual status_t SetBufferGroup( 180 const media_source &for_source, 181 BBufferGroup * group); 182 /* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */ 183 /* Repeat for each line where the clipping is different from the previous line. */ 184 /* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */ 185 /* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */ 186 /* Any non-0 field of 'display' means that that field changed, and if you don't support */ 187 /* that change, you should return an error and ignore the request. Note that the buffer */ 188 /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ 189 /* be adhered to. */ 190virtual status_t VideoClippingChanged( 191 const media_source &for_source, 192 int16 num_shorts, 193 int16 *clip_data, 194 const media_video_display_info &display, 195 int32 *_deprecated_); 196 /* Iterates over all outputs and maxes the latency found */ 197virtual status_t GetLatency(bigtime_t *out_latency); 198virtual status_t PrepareToConnect( 199 const media_source &what, 200 const media_destination &where, 201 media_format *format, 202 media_source *out_source, 203 char *out_name); 204virtual void Connect( 205 status_t error, 206 const media_source &source, 207 const media_destination &destination, 208 const media_format &format, 209 char *io_name); 210virtual void Disconnect( 211 const media_source &what, 212 const media_destination &where); 213virtual void LateNoticeReceived( 214 const media_source &what, 215 bigtime_t how_much, 216 bigtime_t performance_time); 217virtual void EnableOutput( 218 const media_source &what, 219 bool enabled, 220 int32 *_deprecated_); 221virtual status_t SetPlayRate( 222 int32 numer, 223 int32 denom); 224 225virtual void AdditionalBufferRequested( // used to be Reserved 0 226 const media_source & source, 227 media_buffer_id prev_buffer, 228 bigtime_t prev_time, 229 const media_seek_tag *prev_tag); // may be NULL 230 231virtual void LatencyChanged( // used to be Reserved 1 232 const media_source & source, 233 const media_destination & destination, 234 bigtime_t new_latency, 235 uint32 flags); 236 237 238 protected: 239 /* you must override to handle your events! */ 240 /* you should not call HandleEvent directly */ 241 virtual void HandleEvent( const media_timed_event *event, 242 bigtime_t lateness, 243 bool realTimeEvent = false); 244 245 /* override to clean up custom events you have added to your queue */ 246 virtual void CleanUpEvent(const media_timed_event *event); 247 248 /* called from Offline mode to determine the current time of the node */ 249 /* update your internal information whenever it changes */ 250 virtual bigtime_t OfflineTime(); 251 252 /* override only if you know what you are doing! */ 253 /* otherwise much badness could occur */ 254 /* the actual control loop function: */ 255 /* waits for messages, Pops events off the queue and calls DispatchEvent */ 256 virtual void ControlLoop(); 257 258 259protected: 260 261virtual status_t HandleStart( 262 const media_timed_event *event, 263 bigtime_t lateness, 264 bool realTimeEvent = false); 265virtual status_t HandleSeek( 266 const media_timed_event *event, 267 bigtime_t lateness, 268 bool realTimeEvent = false); 269virtual status_t HandleWarp( 270 const media_timed_event *event, 271 bigtime_t lateness, 272 bool realTimeEvent = false); 273virtual status_t HandleStop( 274 const media_timed_event *event, 275 bigtime_t lateness, 276 bool realTimeEvent = false); 277virtual status_t HandleBuffer( 278 const media_timed_event *event, 279 bigtime_t lateness, 280 bool realTimeEvent = false); 281virtual status_t HandleDataStatus( 282 const media_timed_event *event, 283 bigtime_t lateness, 284 bool realTimeEvent = false); 285virtual status_t HandleParameter( 286 const media_timed_event *event, 287 bigtime_t lateness, 288 bool realTimeEvent = false); 289 290protected: 291 292//void CreateBufferGroup(MediaOutputInfo *output_info); 293void ComputeInternalLatency(); 294 295public: 296 297static void GetFlavor(flavor_info *outInfo, int32 id); 298 299private: 300 media_input *CreateInput(uint32 inputID); 301 void ClearInput(media_input *input); 302 media_input *GetInput(const media_source &source); 303 media_input *GetInput(const media_destination &destination); 304 media_input *GetInput(const int32 id); 305 306static void GetInputFormat(media_format *outFormat); 307static void GetOutputFormat(media_format *outFormat); 308 309protected: 310 311virtual status_t AddRequirements(media_format *format); 312 313private: 314 315 status_t fInitCheckStatus; 316 317 BMediaAddOn *fAddOn; 318 319 media_input fInitialInput; 320 std::vector<media_input *> fConnectedInputs; 321 media_output fOutput; 322 323 bigtime_t fDownstreamLatency; 324 bigtime_t fInternalLatency; 325 326 BufferMixer bufferMixer; 327 328}; 329 330#endif /* _VIDEO_MIXER_NODE_H */ 331