1 // MediaOutputInfo.cpp 2 // 3 // Andrew Bachmann, 2002 4 // 5 // A class to encapsulate and manipulate 6 // all the information for a particular 7 // output of a media node. 8 9 #include <MediaDefs.h> 10 #include <BufferGroup.h> 11 #include <BufferProducer.h> 12 #include <stdio.h> 13 #include <string.h> 14 #include "MediaOutputInfo.h" 15 #include "misc.h" 16 17 MediaOutputInfo::MediaOutputInfo(BBufferProducer * node, char * name) { 18 producer = node; 19 // null some fields 20 bufferGroup = 0; 21 bufferPeriod = 0; 22 // start enabled 23 outputEnabled = true; 24 // don't overwrite available space, and be sure to terminate 25 strncpy(output.name,name,B_MEDIA_NAME_LENGTH-1); 26 output.name[B_MEDIA_NAME_LENGTH-1] = '\0'; 27 // initialize the output 28 output.node = media_node::null; 29 output.source = media_source::null; 30 output.destination = media_destination::null; 31 } 32 33 MediaOutputInfo::~MediaOutputInfo() { 34 if (bufferGroup != 0) { 35 BBufferGroup * group = bufferGroup; 36 bufferGroup = 0; 37 delete group; 38 } 39 } 40 41 status_t MediaOutputInfo::SetBufferGroup(BBufferGroup * group) { 42 if (bufferGroup != 0) { 43 if (bufferGroup == group) { 44 return B_OK; // time saver 45 } 46 delete bufferGroup; 47 } 48 bufferGroup = group; 49 } 50 51 // They made an offer to us. We should make sure that the offer is 52 // acceptable, and then we can add any requirements we have on top of 53 // that. We leave wildcards for anything that we don't care about. 54 status_t MediaOutputInfo::FormatProposal(media_format * format) 55 { 56 if (format == 0) { 57 fprintf(stderr,"<- B_BAD_VALUE\n"); 58 return B_BAD_VALUE; // no crashing 59 } 60 // Be's format_is_compatible doesn't work, 61 // so use our format_is_acceptible instead 62 if (!format_is_acceptible(*format,generalFormat)) { 63 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 64 return B_MEDIA_BAD_FORMAT; 65 } 66 // XXX: test because we don't trust them! 67 format->SpecializeTo(&wildcardedFormat); 68 return B_OK; 69 } 70 71 // Presumably we have already agreed with them that this format is 72 // okay. But just in case, we check the offer. (and complain if it 73 // is invalid) Then as the last thing we do, we get rid of any 74 // remaining wilcards. 75 status_t MediaOutputInfo::FormatChangeRequested(const media_destination & destination, 76 media_format * io_format) 77 { 78 if (io_format == 0) { 79 fprintf(stderr,"<- B_BAD_VALUE\n"); 80 return B_BAD_VALUE; // no crashing 81 } 82 status_t status = FormatProposal(io_format); 83 if (status != B_OK) { 84 fprintf(stderr,"<- MediaOutputInfo::FormatProposal failed\n"); 85 *io_format = generalFormat; 86 return status; 87 } 88 io_format->SpecializeTo(&fullySpecifiedFormat); 89 return B_OK; 90 } 91 92 status_t MediaOutputInfo::PrepareToConnect(const media_destination & where, 93 media_format * format, 94 media_source * out_source, 95 char * out_name) 96 { 97 if (output.destination != media_destination::null) { 98 fprintf(stderr,"<- B_MEDIA_ALREADY_CONNECTED\n"); 99 return B_MEDIA_ALREADY_CONNECTED; 100 } 101 status_t status = FormatChangeRequested(where,format); 102 if (status != B_OK) { 103 fprintf(stderr,"<- MediaOutputInfo::FormatChangeRequested failed\n"); 104 return status; 105 } 106 *out_source = output.source; 107 output.destination = where; 108 strncpy(out_name,output.name,B_MEDIA_NAME_LENGTH-1); 109 out_name[B_MEDIA_NAME_LENGTH] = '\0'; 110 return B_OK; 111 } 112 113 status_t MediaOutputInfo::Connect(const media_destination & destination, 114 const media_format & format, 115 char * io_name, 116 bigtime_t _downstreamLatency) 117 { 118 if (io_name == 0) { 119 fprintf(stderr,"<- B_BAD_VALUE\n"); 120 return B_BAD_VALUE; 121 } 122 output.destination = destination; 123 output.format = format; 124 strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1); 125 io_name[B_MEDIA_NAME_LENGTH-1] = '\0'; 126 downstreamLatency = _downstreamLatency; // must be set before create buffer group 127 128 status_t status = CreateBufferGroup(); // also initializes buffer period 129 if (status != B_OK) { 130 output.destination = media_destination::null; 131 output.format = generalFormat; 132 return status; 133 } 134 return B_OK; 135 } 136 137 status_t MediaOutputInfo::Disconnect() 138 { 139 output.destination = media_destination::null; 140 output.format = generalFormat; 141 if (bufferGroup != 0) { 142 BBufferGroup * group = bufferGroup; 143 bufferGroup = 0; 144 delete group; 145 } 146 } 147 148 status_t MediaOutputInfo::EnableOutput(bool enabled) 149 { 150 outputEnabled = enabled; 151 return B_OK; 152 } 153 154 status_t MediaOutputInfo::AdditionalBufferRequested( 155 media_buffer_id prev_buffer, 156 bigtime_t prev_time, 157 const media_seek_tag * prev_tag) 158 { 159 // XXX: implement me 160 return B_OK; 161 } 162 163 // protected: 164 165 status_t MediaOutputInfo::CreateBufferGroup() { 166 bufferPeriod = ComputeBufferPeriod(); 167 168 if (bufferGroup == 0) { 169 int32 count = int32(downstreamLatency/bufferPeriod)+2; 170 fprintf(stderr," downstream latency = %lld, buffer period = %lld, buffer count = %i\n", 171 downstreamLatency,bufferPeriod,count); 172 173 // allocate the buffers 174 bufferGroup = new BBufferGroup(ComputeBufferSize(),count); 175 if (bufferGroup == 0) { 176 fprintf(stderr,"<- B_NO_MEMORY\n"); 177 return B_NO_MEMORY; 178 } 179 status_t status = bufferGroup->InitCheck(); 180 if (status != B_OK) { 181 fprintf(stderr,"<- BufferGroup initialization failed\n"); 182 BBufferGroup * group = bufferGroup; 183 bufferGroup = 0; 184 delete group; 185 return status; 186 } 187 } 188 return B_OK; 189 } 190 191 // public: 192 193 uint32 MediaOutputInfo::ComputeBufferSize() { 194 return ComputeBufferSize(output.format); 195 } 196 197 // returns result in # of bytes 198 uint32 MediaOutputInfo::ComputeBufferSize(const media_format & format) { 199 uint64 bufferSize = 1024; // default 1024 bytes 200 switch (format.type) { 201 case B_MEDIA_MULTISTREAM: 202 bufferSize = format.u.multistream.max_chunk_size; 203 break; 204 case B_MEDIA_ENCODED_VIDEO: 205 bufferSize = format.u.encoded_video.frame_size; 206 break; 207 case B_MEDIA_RAW_VIDEO: 208 if (format.u.raw_video.interlace == 0) { 209 // okay, you have no fields, you need no space, right? 210 bufferSize = 0; 211 } else { 212 // this is the size of a *field*, not a frame 213 bufferSize = format.u.raw_video.display.bytes_per_row * 214 format.u.raw_video.display.line_count / 215 format.u.raw_video.interlace; 216 } 217 break; 218 case B_MEDIA_ENCODED_AUDIO: 219 bufferSize = format.u.encoded_audio.frame_size; 220 break; 221 case B_MEDIA_RAW_AUDIO: 222 bufferSize = format.u.raw_audio.buffer_size; 223 break; 224 default: 225 break; 226 } 227 if (bufferSize > INT_MAX) { 228 bufferSize = INT_MAX; 229 } 230 return int32(bufferSize); 231 } 232 233 bigtime_t MediaOutputInfo::ComputeBufferPeriod() { 234 return ComputeBufferPeriod(output.format); 235 } 236 237 // returns result in # of microseconds 238 bigtime_t MediaOutputInfo::ComputeBufferPeriod(const media_format & format) { 239 bigtime_t bufferPeriod = 25*1000; // default 25 milliseconds 240 switch (format.type) { 241 case B_MEDIA_MULTISTREAM: 242 // given a buffer size of 8192 bytes 243 // and a bitrate of 1024 kilobits/millisecond (= 128 bytes/millisecond) 244 // we need to produce a buffer every 64 milliseconds (= every 64000 microseconds) 245 bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) 246 / format.u.multistream.max_bit_rate); 247 break; 248 case B_MEDIA_ENCODED_VIDEO: 249 bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) 250 / format.u.encoded_video.max_bit_rate); 251 break; 252 case B_MEDIA_ENCODED_AUDIO: 253 bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) 254 / format.u.encoded_audio.bit_rate); 255 break; 256 case B_MEDIA_RAW_VIDEO: 257 // Given a field rate of 50.00 fields per second, (PAL) 258 // we need to generate a field/buffer 259 // every 1/50 of a second = 20000 microseconds. 260 bufferPeriod = bigtime_t(1000000.0 261 / format.u.raw_video.field_rate); 262 break; 263 case B_MEDIA_RAW_AUDIO: 264 // Given a sample size of 4 bytes [B_AUDIO_INT] 265 // and a channel count of 2 and a buffer_size 266 // of 256 bytes and a frame_rate of 44100 Hertz (1/sec) 267 // 1 frame = 1 sample/channel. 268 // comes to ?? 269 // this is a guess: 270 bufferPeriod = bigtime_t(1000000.0 * ComputeBufferSize(format) 271 / (format.u.raw_audio.format 272 & media_raw_audio_format::B_AUDIO_SIZE_MASK) 273 / format.u.raw_audio.channel_count 274 / format.u.raw_audio.frame_rate); 275 break; 276 default: 277 break; 278 } 279 return bufferPeriod; 280 } 281 282 283