xref: /haiku/src/add-ons/media/media-add-ons/video_mixer/BufferMixer.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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++ = ALPHABLEND(c1, *destination, alpha);
67 		*destination++ = ALPHABLEND(c2, *destination, alpha);
68 		*destination++ = ALPHABLEND(c3, *destination, alpha);
69 		*destination++ = 0x00;
70 	}
71 }
72 
73 void
74 BufferMixer::AddBuffer(int32 id, BBuffer *buffer, bool isPrimary) {
75 	BBuffer *oldBuffer;
76 
77 	if (isPrimary) {
78 		oldBuffer = groupedBuffers[0];
79 		groupedBuffers[0] = buffer;
80 	} else {
81 		oldBuffer = groupedBuffers[id];
82 		groupedBuffers[id] = buffer;
83 	}
84 
85 	if (oldBuffer != NULL) {
86 		oldBuffer->Recycle();
87 	}
88 }
89 
90 void
91 BufferMixer::RemoveBuffer(int32 id) {
92 	BBuffer *oldBuffer;
93 
94 	if (id < groupedBuffers.size()) {
95 		oldBuffer = groupedBuffers[id];
96 		groupedBuffers[id] = NULL;
97 
98 		if (oldBuffer != NULL) {
99 			oldBuffer->Recycle();
100 		}
101 	}
102 }
103