1 /*
2  * filter_watermark.c -- watermark filter
3  * Copyright (C) 2003-2014 Meltytech, LLC
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include <framework/mlt_filter.h>
21 #include <framework/mlt_factory.h>
22 #include <framework/mlt_frame.h>
23 #include <framework/mlt_producer.h>
24 #include <framework/mlt_transition.h>
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 /** Do it :-).
31 */
32 
filter_get_image(mlt_frame frame,uint8_t ** image,mlt_image_format * format,int * width,int * height,int writable)33 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
34 {
35 	// Error we will return
36 	int error = 0;
37 
38 	// Get the watermark filter object
39 	mlt_filter filter = mlt_frame_pop_service( frame );
40 
41 	// Get the properties of the filter
42 	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
43 
44 	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
45 
46 	// Get the producer from the filter
47 	mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL );
48 
49 	// Get the composite from the filter
50 	mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL );
51 
52 	// Get the resource to use
53 	char *resource = mlt_properties_get( properties, "resource" );
54 
55 	// Get the old resource
56 	char *old_resource = mlt_properties_get( properties, "_old_resource" );
57 
58 	// Create a composite if we don't have one
59 	if ( composite == NULL )
60 	{
61 		// Create composite via the factory
62 		mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
63 		composite = mlt_factory_transition( profile, "composite", NULL );
64 
65 		// Register the composite for reuse/destruction
66 		if ( composite != NULL )
67 			mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL );
68 	}
69 
70 	// If we have one
71 	if ( composite != NULL )
72 	{
73 		// Get the properties
74 		mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite );
75 
76 		// Pass all the composite. properties on the filter down
77 		mlt_properties_pass( composite_properties, properties, "composite." );
78 
79 		if ( mlt_properties_get( properties, "composite.out" ) == NULL )
80 			mlt_properties_set_int( composite_properties, "out", mlt_properties_get_int( properties, "_out" ) );
81 
82 		// Force a refresh
83 		mlt_properties_set_int( composite_properties, "refresh", 1 );
84 	}
85 
86 	// Create a producer if don't have one
87 	if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) )
88 	{
89 		// Get the factory producer service
90 		char *factory = mlt_properties_get( properties, "factory" );
91 
92 		// Create the producer
93 		mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
94 		producer = mlt_factory_producer( profile, factory, resource );
95 
96 		// If we have one
97 		if ( producer != NULL )
98 		{
99 			// Register the producer for reuse/destruction
100 			mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
101 
102 			// Ensure that we loop
103 			mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" );
104 
105 			// Set the old resource
106 			mlt_properties_set( properties, "_old_resource", resource );
107 		}
108 	}
109 
110 	if ( producer != NULL )
111 	{
112 		// Get the producer properties
113 		mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
114 
115 		// Now pass all producer. properties on the filter down
116 		mlt_properties_pass( producer_properties, properties, "producer." );
117 	}
118 
119 	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
120 
121 	// Process all remaining filters first
122 	*format = mlt_image_yuv422;
123 	error = mlt_frame_get_image( frame, image, format, width, height, 0 );
124 
125 	// Only continue if we have both producer and composite
126 	if ( !error && composite != NULL && producer != NULL )
127 	{
128 		// Get the service of the producer
129 		mlt_service service = MLT_PRODUCER_SERVICE( producer );
130 
131 		// Create a temporary frame so the original stays in tact.
132 		mlt_frame a_frame = mlt_frame_clone( frame, 0 );
133 
134 		// We will get the 'b frame' from the producer
135 		mlt_frame b_frame = NULL;
136 
137 		// Get the original producer position
138 		mlt_position position = mlt_filter_get_position( filter, frame );
139 
140 		// Make sure the producer is in the correct position
141 		mlt_producer_seek( producer, position );
142 
143 		// Resetting position to appease the composite transition
144 		mlt_frame_set_position( a_frame, position );
145 
146 		// Get the b frame and process with composite if successful
147 		if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 )
148 		{
149 			// Get the a and b frame properties
150 			mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
151 			mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );
152 			mlt_profile profile = mlt_service_profile( service );
153 
154 			// Set the b frame to be in the same position and have same consumer requirements
155 			mlt_frame_set_position( b_frame, position );
156 			mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) );
157 
158 			// Check for the special case - no aspect ratio means no problem :-)
159 			if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 )
160 				mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( profile ) );
161 			if ( mlt_frame_get_aspect_ratio( a_frame ) == 0 )
162 				mlt_frame_set_aspect_ratio( a_frame, mlt_profile_sar( profile ) );
163 
164 			if ( mlt_properties_get_int( properties, "distort" ) )
165 			{
166 				mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( composite ), "distort", 1 );
167 				mlt_properties_set_int( a_props, "distort", 1 );
168 				mlt_properties_set_int( b_props, "distort", 1 );
169 			}
170 
171 			*format = mlt_image_yuv422;
172 			if ( mlt_properties_get_int( properties, "reverse" ) == 0 )
173 			{
174 				// Apply all filters that are attached to this filter to the b frame
175 				mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 );
176 
177 				// Process the frame
178 				mlt_transition_process( composite, a_frame, b_frame );
179 
180 				// Get the image
181 				error = mlt_frame_get_image( a_frame, image, format, width, height, 1 );
182 			}
183 			else
184 			{
185 				char temp[ 132 ];
186 				int count = 0;
187 				uint8_t *alpha = NULL;
188 				const char *rescale = mlt_properties_get( a_props, "rescale.interp" );
189 				if ( rescale == NULL || !strcmp( rescale, "none" ) )
190 					rescale = "hyper";
191 				mlt_transition_process( composite, b_frame, a_frame );
192 				mlt_properties_set_int( a_props, "consumer_deinterlace", 1 );
193 				mlt_properties_set_int( b_props, "consumer_deinterlace", 1 );
194 				mlt_properties_set( a_props, "rescale.interp", rescale );
195 				mlt_properties_set( b_props, "rescale.interp", rescale );
196 				mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 );
197 				error = mlt_frame_get_image( b_frame, image, format, width, height, 1 );
198 				alpha = mlt_frame_get_alpha_mask( b_frame );
199 				mlt_frame_set_image( frame, *image, *width * *height * 2, NULL );
200 				mlt_frame_set_alpha( frame, alpha, *width * *height, NULL );
201 				mlt_properties_set_int( a_props, "width", *width );
202 				mlt_properties_set_int( a_props, "height", *height );
203 				mlt_properties_set_int( a_props, "progressive", 1 );
204 				mlt_properties_inc_ref( b_props );
205 				strcpy( temp, "_b_frame" );
206 				while( mlt_properties_get_data( a_props, temp, NULL ) != NULL )
207 					sprintf( temp, "_b_frame%d", count ++ );
208 				mlt_properties_set_data( a_props, temp, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
209 			}
210 		}
211 
212 		// Close the temporary frames
213 		mlt_frame_close( a_frame );
214 		mlt_frame_close( b_frame );
215 	}
216 
217 	return error;
218 }
219 
220 /** Filter processing.
221 */
222 
filter_process(mlt_filter filter,mlt_frame frame)223 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
224 {
225 	// Get the properties of the frame
226 	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
227 
228 	// Assign the frame out point to the filter (just in case we need it later)
229 	mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_out", mlt_properties_get_int( properties, "out" ) );
230 
231 	// Push the filter on to the stack
232 	mlt_frame_push_service( frame, filter );
233 
234 	// Push the get_image on to the stack
235 	mlt_frame_push_get_image( frame, filter_get_image );
236 
237 	return frame;
238 }
239 
240 /** Constructor for the filter.
241 */
242 
filter_watermark_init(mlt_profile profile,mlt_service_type type,const char * id,char * arg)243 mlt_filter filter_watermark_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
244 {
245 	mlt_filter filter = mlt_filter_new( );
246 	if ( filter != NULL )
247 	{
248 		mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
249 		filter->process = filter_process;
250 		mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) );
251 		if ( arg != NULL )
252 			mlt_properties_set( properties, "resource", arg );
253 		// Ensure that attached filters are handled privately
254 		mlt_properties_set_int( properties, "_filter_private", 1 );
255 	}
256 	return filter;
257 }
258 
259