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 // Be's format_is_compatible doesn't work, 57 // so use our format_is_acceptible instead 58 if (!format_is_acceptible(*format,generalFormat)) { 59 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 60 return B_MEDIA_BAD_FORMAT; 61 } 62 // XXX: test because we don't trust them! 63 format->SpecializeTo(&wildcardedFormat); 64 return B_OK; 65 } 66 67 // Presumably we have already agreed with them that this format is 68 // okay. But just in case, we check the offer. (and complain if it 69 // is invalid) Then as the last thing we do, we get rid of any 70 // remaining wilcards. 71 status_t MediaOutputInfo::FormatChangeRequested(const media_destination & destination, 72 media_format * io_format) 73 { 74 status_t status = FormatProposal(io_format); 75 if (status != B_OK) { 76 fprintf(stderr,"<- MediaOutputInfo::FormatProposal failed\n"); 77 *io_format = generalFormat; 78 return status; 79 } 80 io_format->SpecializeTo(&fullySpecifiedFormat); 81 return B_OK; 82 } 83 84 status_t MediaOutputInfo::PrepareToConnect(const media_destination & where, 85 media_format * format, 86 media_source * out_source, 87 char * out_name) 88 { 89 if (output.destination != media_destination::null) { 90 fprintf(stderr,"<- B_MEDIA_ALREADY_CONNECTED\n"); 91 return B_MEDIA_ALREADY_CONNECTED; 92 } 93 status_t status = FormatChangeRequested(where,format); 94 if (status != B_OK) { 95 fprintf(stderr,"<- MediaOutputInfo::FormatChangeRequested failed\n"); 96 return status; 97 } 98 *out_source = output.source; 99 output.destination = where; 100 strncpy(out_name,output.name,B_MEDIA_NAME_LENGTH-1); 101 out_name[B_MEDIA_NAME_LENGTH] = '\0'; 102 return B_OK; 103 } 104 105 status_t MediaOutputInfo::Connect(const media_destination & destination, 106 const media_format & format, 107 char * io_name, 108 bigtime_t _downstreamLatency) 109 { 110 output.destination = destination; 111 output.format = format; 112 strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1); 113 io_name[B_MEDIA_NAME_LENGTH-1] = '\0'; 114 downstreamLatency = _downstreamLatency; // must be set before create buffer group 115 116 status_t status = CreateBufferGroup(); // also initializes buffer period 117 if (status != B_OK) { 118 output.destination = media_destination::null; 119 output.format = generalFormat; 120 return status; 121 } 122 return B_OK; 123 } 124 125 status_t MediaOutputInfo::Disconnect() 126 { 127 output.destination = media_destination::null; 128 output.format = generalFormat; 129 if (bufferGroup != 0) { 130 BBufferGroup * group = bufferGroup; 131 bufferGroup = 0; 132 delete group; 133 } 134 } 135 136 status_t MediaOutputInfo::EnableOutput(bool enabled) 137 { 138 outputEnabled = enabled; 139 return B_OK; 140 } 141 142 status_t MediaOutputInfo::AdditionalBufferRequested( 143 media_buffer_id prev_buffer, 144 bigtime_t prev_time, 145 const media_seek_tag * prev_tag) 146 { 147 // XXX: implement me 148 return B_OK; 149 } 150 151 // protected: 152 153 status_t MediaOutputInfo::CreateBufferGroup() { 154 bufferPeriod = ComputeBufferPeriod(); 155 156 if (bufferGroup == 0) { 157 int32 count = int32(downstreamLatency/bufferPeriod)+2; 158 fprintf(stderr," downstream latency = %lld, buffer period = %lld, buffer count = %i\n", 159 downstreamLatency,bufferPeriod,count); 160 161 // allocate the buffers 162 bufferGroup = new BBufferGroup(ComputeBufferSize(),count); 163 if (bufferGroup == 0) { 164 fprintf(stderr,"<- B_NO_MEMORY\n"); 165 return B_NO_MEMORY; 166 } 167 status_t status = bufferGroup->InitCheck(); 168 if (status != B_OK) { 169 fprintf(stderr,"<- BufferGroup initialization failed\n"); 170 BBufferGroup * group = bufferGroup; 171 bufferGroup = 0; 172 delete group; 173 return status; 174 } 175 } 176 return B_OK; 177 } 178 179 // public: 180 181 uint32 MediaOutputInfo::ComputeBufferSize() { 182 return ComputeBufferSize(output.format); 183 } 184 185 // returns result in # of bytes 186 uint32 MediaOutputInfo::ComputeBufferSize(const media_format & format) { 187 uint64 bufferSize = 1024; // default 1024 bytes 188 switch (format.type) { 189 case B_MEDIA_MULTISTREAM: 190 bufferSize = format.u.multistream.max_chunk_size; 191 break; 192 case B_MEDIA_ENCODED_VIDEO: 193 bufferSize = format.u.encoded_video.frame_size; 194 break; 195 case B_MEDIA_RAW_VIDEO: 196 if (format.u.raw_video.interlace == 0) { 197 // okay, you have no fields, you need no space, right? 198 bufferSize = 0; 199 } else { 200 // this is the size of a *field*, not a frame 201 bufferSize = format.u.raw_video.display.bytes_per_row * 202 format.u.raw_video.display.line_count / 203 format.u.raw_video.interlace; 204 } 205 break; 206 case B_MEDIA_ENCODED_AUDIO: 207 bufferSize = format.u.encoded_audio.frame_size; 208 break; 209 case B_MEDIA_RAW_AUDIO: 210 bufferSize = format.u.raw_audio.buffer_size; 211 break; 212 default: 213 break; 214 } 215 if (bufferSize > INT_MAX) { 216 bufferSize = INT_MAX; 217 } 218 return int32(bufferSize); 219 } 220 221 bigtime_t MediaOutputInfo::ComputeBufferPeriod() { 222 return ComputeBufferPeriod(output.format); 223 } 224 225 // returns result in # of microseconds 226 bigtime_t MediaOutputInfo::ComputeBufferPeriod(const media_format & format) { 227 bigtime_t bufferPeriod = 25*1000; // default 25 milliseconds 228 switch (format.type) { 229 case B_MEDIA_MULTISTREAM: 230 // given a buffer size of 8192 bytes 231 // and a bitrate of 1024 kilobits/millisecond (= 128 bytes/millisecond) 232 // we need to produce a buffer every 64 milliseconds (= every 64000 microseconds) 233 bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) 234 / format.u.multistream.max_bit_rate); 235 break; 236 case B_MEDIA_ENCODED_VIDEO: 237 bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) 238 / format.u.encoded_video.max_bit_rate); 239 break; 240 case B_MEDIA_ENCODED_AUDIO: 241 bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) 242 / format.u.encoded_audio.bit_rate); 243 break; 244 case B_MEDIA_RAW_VIDEO: 245 // Given a field rate of 50.00 fields per second, (PAL) 246 // we need to generate a field/buffer 247 // every 1/50 of a second = 20000 microseconds. 248 bufferPeriod = bigtime_t(1000000.0 249 / format.u.raw_video.field_rate); 250 break; 251 case B_MEDIA_RAW_AUDIO: 252 // Given a sample size of 4 bytes [B_AUDIO_INT] 253 // and a channel count of 2 and a buffer_size 254 // of 256 bytes and a frame_rate of 44100 Hertz (1/sec) 255 // 1 frame = 1 sample/channel. 256 // comes to ?? 257 // this is a guess: 258 bufferPeriod = bigtime_t(1000000.0 * ComputeBufferSize(format) 259 / (format.u.raw_audio.format 260 & media_raw_audio_format::B_AUDIO_SIZE_MASK) 261 / format.u.raw_audio.channel_count 262 / format.u.raw_audio.frame_rate); 263 break; 264 default: 265 break; 266 } 267 return bufferPeriod; 268 } 269 270 271