xref: /haiku/src/kits/media/Buffer.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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 "MediaDebug.h"
41 #include "MediaMisc.h"
42 #include "DataExchange.h"
43 #include "SharedBufferList.h"
44 
45 
46 using namespace BPrivate::media;
47 
48 
49 //	#pragma mark - buffer_clone_info
50 
51 
52 buffer_clone_info::buffer_clone_info()
53 {
54 	CALLED();
55 	buffer = 0;
56 	area = 0;
57 	offset = 0;
58 	size = 0;
59 	flags = 0;
60 }
61 
62 
63 buffer_clone_info::~buffer_clone_info()
64 {
65 	CALLED();
66 }
67 
68 
69 //	#pragma mark - public BBuffer
70 
71 
72 void*
73 BBuffer::Data()
74 {
75 	CALLED();
76 	return fData;
77 }
78 
79 
80 size_t
81 BBuffer::SizeAvailable()
82 {
83 	CALLED();
84 	return fSize;
85 }
86 
87 
88 size_t
89 BBuffer::SizeUsed()
90 {
91 	CALLED();
92 	return fMediaHeader.size_used;
93 }
94 
95 
96 void
97 BBuffer::SetSizeUsed(size_t size_used)
98 {
99 	CALLED();
100 	fMediaHeader.size_used = min_c(size_used, fSize);
101 }
102 
103 
104 uint32
105 BBuffer::Flags()
106 {
107 	CALLED();
108 	return fFlags;
109 }
110 
111 
112 void
113 BBuffer::Recycle()
114 {
115 	CALLED();
116 	if (fBufferList == NULL)
117 		return;
118 	fFlags &= ~BUFFER_TO_RECLAIM;
119 	if ((fFlags & BUFFER_MARKED_FOR_DELETION) != 0)
120 		delete this;
121 	else
122 		fBufferList->RecycleBuffer(this);
123 }
124 
125 
126 buffer_clone_info
127 BBuffer::CloneInfo() const
128 {
129 	CALLED();
130 	buffer_clone_info info;
131 
132 	info.buffer = fMediaHeader.buffer;
133 	info.area = fArea;
134 	info.offset = fOffset;
135 	info.size = fSize;
136 	info.flags = fFlags;
137 
138 	return info;
139 }
140 
141 
142 media_buffer_id
143 BBuffer::ID()
144 {
145 	CALLED();
146 	return fMediaHeader.buffer;
147 }
148 
149 
150 media_type
151 BBuffer::Type()
152 {
153 	CALLED();
154 	return fMediaHeader.type;
155 }
156 
157 
158 media_header*
159 BBuffer::Header()
160 {
161 	CALLED();
162 	return &fMediaHeader;
163 }
164 
165 
166 media_audio_header*
167 BBuffer::AudioHeader()
168 {
169 	CALLED();
170 	return &fMediaHeader.u.raw_audio;
171 }
172 
173 
174 media_video_header*
175 BBuffer::VideoHeader()
176 {
177 	CALLED();
178 	return &fMediaHeader.u.raw_video;
179 }
180 
181 
182 size_t
183 BBuffer::Size()
184 {
185 	CALLED();
186 	return SizeAvailable();
187 }
188 
189 
190 // #pragma mark - private BBuffer
191 
192 
193 BBuffer::BBuffer(const buffer_clone_info& info)
194 	:
195 	fBufferList(NULL),
196 	fArea(-1),
197 	fData(NULL),
198 	fOffset(0),
199 	fSize(0),
200 	fFlags(0)
201 {
202 	CALLED();
203 
204 	// Ensure that the media_header is clean
205 	memset(&fMediaHeader, 0, sizeof(fMediaHeader));
206 	// special case for BSmallBuffer
207 	if (info.area == 0 && info.buffer == 0)
208 		return;
209 
210 	// Must be -1 if registration fail
211 	fMediaHeader.buffer = -1;
212 
213 	fBufferList = BPrivate::SharedBufferList::Get();
214 	if (fBufferList == NULL) {
215 		ERROR("BBuffer::BBuffer: BPrivate::SharedBufferList::Get() failed\n");
216 		return;
217 	}
218 
219 	server_register_buffer_request request;
220 	server_register_buffer_reply reply;
221 
222 	request.team = BPrivate::current_team();
223 	request.info = info;
224 
225 	// ask media_server to register this buffer,
226 	// either identified by "buffer" or by area information.
227 	// media_server either has a copy of the area identified
228 	// by "buffer", or creates a new area.
229 	// the information and the area is cached by the media_server
230 	// until the last buffer has been unregistered
231 	// the area_id of the cached area is passed back to us, and we clone it.
232 
233 	if (QueryServer(SERVER_REGISTER_BUFFER, &request, sizeof(request), &reply,
234 			sizeof(reply)) != B_OK) {
235 		ERROR("BBuffer::BBuffer: failed to register buffer with "
236 			"media_server\n");
237 		return;
238 	}
239 
240 	ASSERT(reply.info.buffer > 0);
241 	ASSERT(reply.info.area > 0);
242 	ASSERT(reply.info.size > 0);
243 
244 	fArea = clone_area("a cloned BBuffer", &fData, B_ANY_ADDRESS,
245 		B_READ_AREA | B_WRITE_AREA, reply.info.area);
246 	if (fArea < 0) {
247 		ERROR("BBuffer::BBuffer: buffer cloning failed"
248 			", unregistering buffer\n");
249 		server_unregister_buffer_command cmd;
250 		cmd.team = BPrivate::current_team();
251 		cmd.buffer_id = reply.info.buffer;
252 		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
253 		return;
254 	}
255 
256 	// the response from media server contains enough information
257 	// to clone the memory for this buffer
258 	fSize = reply.info.size;
259 	fFlags = reply.info.flags;
260 	fOffset = reply.info.offset;
261 	fMediaHeader.size_used = 0;
262 	fMediaHeader.buffer = reply.info.buffer;
263 	fData = (char*)fData + fOffset;
264 }
265 
266 
267 BBuffer::~BBuffer()
268 {
269 	CALLED();
270 
271 	// unmap the BufferList
272 	if (fBufferList != NULL)
273 		fBufferList->Put();
274 
275 	// unmap the Data
276 	if (fData != NULL) {
277 		delete_area(fArea);
278 
279 		// Ask media_server to unregister the buffer when the last clone of
280 		// this buffer is gone, media_server will also remove its cached area.
281 		server_unregister_buffer_command cmd;
282 		cmd.team = BPrivate::current_team();
283 		cmd.buffer_id = fMediaHeader.buffer;
284 		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
285 	}
286 }
287 
288 
289 void
290 BBuffer::SetHeader(const media_header* header)
291 {
292 	CALLED();
293 	ASSERT(header->buffer == fMediaHeader.buffer);
294 	if (header->buffer != fMediaHeader.buffer)
295 		debugger("oops");
296 	fMediaHeader = *header;
297 }
298 
299 
300 // #pragma mark - public BSmallBuffer
301 
302 
303 static const buffer_clone_info sSmallBufferInfo;
304 
305 
306 BSmallBuffer::BSmallBuffer()
307 	:
308 	BBuffer(sSmallBufferInfo)
309 {
310 	UNIMPLEMENTED();
311 	debugger("BSmallBuffer::BSmallBuffer called\n");
312 }
313 
314 
315 size_t
316 BSmallBuffer::SmallBufferSizeLimit()
317 {
318 	CALLED();
319 	return 64;
320 }
321 
322 
323