xref: /haiku/src/add-ons/media/media-add-ons/video_mixer/BufferMixer.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
1 /*
2  * Copyright (C) 2010 David McPaul
3  *
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 
7 // This class merges buffers together
8 // Merge is called everytime a primary buffer needs to be passed downstream
9 // This should allow different framerates to be handled by buffering slower
10 // buffer producers and discarding buffers from faster producers
11 // TODO ColorConversion
12 
13 #include "BufferMixer.h"
14 
15 BufferMixer::BufferMixer() {
16 }
17 
18 BufferMixer::~BufferMixer() {
19 }
20 
21 bool
22 BufferMixer::isBufferAvailable() {
23 	return groupedBuffers[0] != NULL;
24 }
25 
26 // Should only be called after checking with isBufferAvailable
27 BBuffer *
28 BufferMixer::GetOutputBuffer() {
29 	// Do the merging of all buffers in the groupedBuffers map
30 	// into the primary buffer and return that buffer.
31 	// The primary buffer is removed;
32 
33 	BBuffer *outputBuffer = groupedBuffers[0];
34 	groupedBuffers[0] = NULL;
35 
36 	std::map<int32, BBuffer*>::iterator each;
37 
38 	for (each=groupedBuffers.begin(); each != groupedBuffers.end(); each++) {
39 		if (each->second != outputBuffer) {
40 			if (each->second != NULL) {
41 				Merge(each->second, outputBuffer);
42 			}
43 		}
44 	}
45 
46 	return outputBuffer;
47 }
48 
49 #define ALPHABLEND(source, destination, alpha) (((destination) * (256 - (alpha)) + (source) * (alpha)) >> 8)
50 
51 void
52 BufferMixer::Merge(BBuffer *input, BBuffer *output) {
53 	// Currently only deals with RGBA32
54 
55 	uint8 *source = (uint8 *)input->Data();
56 	uint8 *destination = (uint8 *)output->Data();
57 	uint32 size = input->Header()->size_used / 4;
58 	uint8 alpha = 0;
59 	uint8 c1, c2, c3;
60 
61 	for (uint32 i=0; i<size; i++) {
62 		c1    = *source++;
63 		c2    = *source++;
64 		c3    = *source++;
65 		alpha = *source++;
66 		destination[0] = ALPHABLEND(c1, destination[0], alpha);
67 		destination[1] = ALPHABLEND(c2, destination[1], alpha);
68 		destination[2] = ALPHABLEND(c3, destination[2], alpha);
69 		destination[3] = 0x00;
70 		destination += 4;
71 	}
72 }
73 
74 void
75 BufferMixer::AddBuffer(int32 id, BBuffer *buffer, bool isPrimary) {
76 	BBuffer *oldBuffer;
77 
78 	if (isPrimary) {
79 		oldBuffer = groupedBuffers[0];
80 		groupedBuffers[0] = buffer;
81 	} else {
82 		oldBuffer = groupedBuffers[id];
83 		groupedBuffers[id] = buffer;
84 	}
85 
86 	if (oldBuffer != NULL) {
87 		oldBuffer->Recycle();
88 	}
89 }
90 
91 void
92 BufferMixer::RemoveBuffer(int32 id) {
93 	BBuffer *oldBuffer;
94 
95 	if (uint32(id) < groupedBuffers.size()) {
96 		oldBuffer = groupedBuffers[id];
97 		groupedBuffers[id] = NULL;
98 
99 		if (oldBuffer != NULL) {
100 			oldBuffer->Recycle();
101 		}
102 	}
103 }
104