xref: /haiku/src/kits/media/Buffer.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*
7  * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files or portions
11  * thereof (the "Software"), to deal in the Software without restriction,
12  * including without limitation the rights to use, copy, modify, merge,
13  * publish, distribute, sublicense, and/or sell copies of the Software,
14  * and to permit persons to whom the Software is furnished to do so, subject
15  * to the following conditions:
16  *
17  *  * Redistributions of source code must retain the above copyright notice,
18  *    this list of conditions and the following disclaimer.
19  *
20  *  * Redistributions in binary form must reproduce the above copyright notice
21  *    in the  binary, as well as this list of conditions and the following
22  *    disclaimer in the documentation and/or other materials provided with
23  *    the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31  * THE SOFTWARE.
32  */
33 
34 
35 #include <Buffer.h>
36 
37 #include <AppMisc.h>
38 #include <MediaDefs.h>
39 
40 #include "debug.h"
41 #include "DataExchange.h"
42 #include "SharedBufferList.h"
43 
44 
45 using namespace BPrivate::media;
46 
47 
48 //	#pragma mark - buffer_clone_info
49 
50 
51 buffer_clone_info::buffer_clone_info()
52 {
53 	CALLED();
54 	buffer = 0;
55 	area = 0;
56 	offset = 0;
57 	size = 0;
58 	flags = 0;
59 }
60 
61 
62 buffer_clone_info::~buffer_clone_info()
63 {
64 	CALLED();
65 }
66 
67 
68 //	#pragma mark - public BBuffer
69 
70 
71 void*
72 BBuffer::Data()
73 {
74 	CALLED();
75 	return fData;
76 }
77 
78 
79 size_t
80 BBuffer::SizeAvailable()
81 {
82 	CALLED();
83 	return fSize;
84 }
85 
86 
87 size_t
88 BBuffer::SizeUsed()
89 {
90 	CALLED();
91 	return fMediaHeader.size_used;
92 }
93 
94 
95 void
96 BBuffer::SetSizeUsed(size_t size_used)
97 {
98 	CALLED();
99 	fMediaHeader.size_used = min_c(size_used, fSize);
100 }
101 
102 
103 uint32
104 BBuffer::Flags()
105 {
106 	CALLED();
107 	return fFlags;
108 }
109 
110 
111 void
112 BBuffer::Recycle()
113 {
114 	CALLED();
115 	if (fBufferList == NULL)
116 		return;
117 	fBufferList->RecycleBuffer(this);
118 }
119 
120 
121 buffer_clone_info
122 BBuffer::CloneInfo() const
123 {
124 	CALLED();
125 	buffer_clone_info info;
126 
127 	info.buffer = fMediaHeader.buffer;
128 	info.area = fArea;
129 	info.offset = fOffset;
130 	info.size = fSize;
131 	info.flags = fFlags;
132 
133 	return info;
134 }
135 
136 
137 media_buffer_id
138 BBuffer::ID()
139 {
140 	CALLED();
141 	return fMediaHeader.buffer;
142 }
143 
144 
145 media_type
146 BBuffer::Type()
147 {
148 	CALLED();
149 	return fMediaHeader.type;
150 }
151 
152 
153 media_header*
154 BBuffer::Header()
155 {
156 	CALLED();
157 	return &fMediaHeader;
158 }
159 
160 
161 media_audio_header*
162 BBuffer::AudioHeader()
163 {
164 	CALLED();
165 	return &fMediaHeader.u.raw_audio;
166 }
167 
168 
169 media_video_header*
170 BBuffer::VideoHeader()
171 {
172 	CALLED();
173 	return &fMediaHeader.u.raw_video;
174 }
175 
176 
177 size_t
178 BBuffer::Size()
179 {
180 	CALLED();
181 	return SizeAvailable();
182 }
183 
184 
185 // #pragma mark - private BBuffer
186 
187 
188 BBuffer::BBuffer(const buffer_clone_info& info)
189 	:
190 	// must all be NULL/0 if not correctly initialized
191 	fBufferList(NULL),
192 	fData(NULL),
193 	fSize(0)
194 {
195 	CALLED();
196 
197 	fMediaHeader.buffer = 0;
198 		// must be 0 if not registered
199 
200 	// special case for BSmallBuffer
201 	if (info.area == 0 && info.buffer == 0)
202 		return;
203 
204 	fBufferList = BPrivate::SharedBufferList::Get();
205 	if (fBufferList == NULL) {
206 		ERROR("BBuffer::BBuffer: BPrivate::SharedBufferList::Get() failed\n");
207 		return;
208 	}
209 
210 	server_register_buffer_request request;
211 	server_register_buffer_reply reply;
212 
213 	request.team = BPrivate::current_team();
214 	request.info = info;
215 
216 	// ask media_server to register this buffer,
217 	// either identified by "buffer" or by area information.
218 	// media_server either has a copy of the area identified
219 	// by "buffer", or creates a new area.
220 	// the information and the area is cached by the media_server
221 	// until the last buffer has been unregistered
222 	// the area_id of the cached area is passed back to us, and we clone it.
223 
224 	if (QueryServer(SERVER_REGISTER_BUFFER, &request, sizeof(request), &reply,
225 			sizeof(reply)) != B_OK) {
226 		ERROR("BBuffer::BBuffer: failed to register buffer with "
227 			"media_server\n");
228 		return;
229 	}
230 
231 	ASSERT(reply.info.buffer > 0);
232 	ASSERT(reply.info.area > 0);
233 	ASSERT(reply.info.size > 0);
234 
235 	// the response from media server contains enough information
236 	// to clone the memory for this buffer
237 	fSize = reply.info.size;
238 	fFlags = reply.info.flags;
239 	fOffset = reply.info.offset;
240 	fMediaHeader.size_used = 0;
241 	fMediaHeader.buffer = reply.info.buffer;
242 
243 	fArea = clone_area("a cloned BBuffer", &fData, B_ANY_ADDRESS,
244 		B_READ_AREA | B_WRITE_AREA, reply.info.area);
245 	if (fArea < 0) {
246 		// TODO: should unregister buffer here
247 		ERROR("BBuffer::BBuffer: buffer cloning failed\n");
248 		fData = 0;
249 		return;
250 	}
251 
252 	fData = (char*)fData + fOffset;
253 }
254 
255 
256 BBuffer::~BBuffer()
257 {
258 	CALLED();
259 
260 	// unmap the BufferList
261 	if (fBufferList != NULL)
262 		fBufferList->Put();
263 
264 	// unmap the Data
265 	if (fData != NULL) {
266 		delete_area(fArea);
267 
268 		// Ask media_server to unregister the buffer when the last clone of
269 		// this buffer is gone, media_server will also remove its cached area.
270 		server_unregister_buffer_command cmd;
271 		cmd.team = BPrivate::current_team();
272 		cmd.buffer_id = fMediaHeader.buffer;
273 		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
274 	}
275 }
276 
277 
278 void
279 BBuffer::SetHeader(const media_header* header)
280 {
281 	CALLED();
282 	ASSERT(header->buffer == fMediaHeader.buffer);
283 	if (header->buffer != fMediaHeader.buffer)
284 		debugger("oops");
285 	fMediaHeader = *header;
286 }
287 
288 
289 // #pragma mark - public BSmallBuffer
290 
291 
292 static const buffer_clone_info sSmallBufferInfo;
293 
294 
295 BSmallBuffer::BSmallBuffer()
296 	:
297 	BBuffer(sSmallBufferInfo)
298 {
299 	UNIMPLEMENTED();
300 	debugger("BSmallBuffer::BSmallBuffer called\n");
301 }
302 
303 
304 size_t
305 BSmallBuffer::SmallBufferSizeLimit()
306 {
307 	CALLED();
308 	return 64;
309 }
310 
311 
312