1 //    Copyright (C) 2010 Dirk Vanden Boer <dirk.vdb@gmail.com>
2 //
3 //    This program is free software; you can redistribute it and/or modify
4 //    it under the terms of the GNU General Public License as published by
5 //    the Free Software Foundation; either version 2 of the License, or
6 //    (at your option) any later version.
7 //
8 //    This program is distributed in the hope that it will be useful,
9 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //    GNU General Public License for more details.
12 //
13 //    You should have received a copy of the GNU General Public License
14 //    along with this program; if not, write to the Free Software
15 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 
17 #include "videothumbnailerc.h"
18 #include "videothumbnailer.h"
19 #include "filmstripfilter.h"
20 
21 #include <vector>
22 #include <stdexcept>
23 
24 using namespace ffmpegthumbnailer;
25 
26 struct thumbnailer_data
27 {
28     VideoThumbnailer thumbnailer;
29     FilmStripFilter filter;
30     thumbnailer_log_callback log_cb = nullptr;
31 };
32 
trace_message(video_thumbnailer * thumbnailer,ThumbnailerLogLevel lvl,const char * message)33 static void trace_message(video_thumbnailer* thumbnailer, ThumbnailerLogLevel lvl, const char* message)
34 {
35     if (thumbnailer->tdata->log_cb)
36     {
37         thumbnailer->tdata->log_cb(lvl, message);
38     }
39 }
40 
video_thumbnailer_create(void)41 extern "C" video_thumbnailer* video_thumbnailer_create(void)
42 {
43     video_thumbnailer* thumbnailer = new video_thumbnailer_struct();
44 
45     thumbnailer->thumbnail_size             = 128;
46     thumbnailer->seek_percentage            = 10;
47     thumbnailer->seek_time                  = nullptr;
48     thumbnailer->overlay_film_strip         = 0;
49     thumbnailer->workaround_bugs            = 0;
50     thumbnailer->thumbnail_image_quality    = 8;
51     thumbnailer->thumbnail_image_type       = Png;
52     thumbnailer->maintain_aspect_ratio      = 1;
53     thumbnailer->prefer_embedded_metadata   = 0;
54     thumbnailer->av_format_context          = nullptr;
55     thumbnailer->tdata                      = new thumbnailer_data();
56 
57     return thumbnailer;
58 }
59 
video_thumbnailer_destroy(video_thumbnailer * thumbnailer)60 extern "C" void video_thumbnailer_destroy(video_thumbnailer* thumbnailer)
61 {
62     delete thumbnailer->tdata;
63     delete thumbnailer;
64 }
65 
video_thumbnailer_create_image_data(void)66 extern "C" image_data* video_thumbnailer_create_image_data(void)
67 {
68     image_data* data        = new image_data();
69 
70     data->image_data_ptr    = 0;
71     data->image_data_size   = 0;
72     data->image_data_width  = 0;
73     data->image_data_height = 0;
74     data->internal_data     = new std::vector<uint8_t>();
75 
76     return data;
77 }
78 
video_thumbnailer_destroy_image_data(image_data * data)79 extern "C" void video_thumbnailer_destroy_image_data(image_data* data)
80 {
81     data->image_data_ptr    = 0;
82     data->image_data_size   = 0;
83     data->image_data_width  = 0;
84     data->image_data_height = 0;
85 
86     std::vector<uint8_t>* dataVector = reinterpret_cast<std::vector<uint8_t>* >(data->internal_data);
87     delete dataVector;
88     data->internal_data     = 0;
89 
90     delete data;
91 }
92 
setProperties(video_thumbnailer * thumbnailer)93 static void setProperties(video_thumbnailer* thumbnailer)
94 {
95     auto& videoThumbnailer = thumbnailer->tdata->thumbnailer;
96 
97     if (thumbnailer->thumbnail_size >= 0)
98     {
99         videoThumbnailer.setThumbnailSize(thumbnailer->thumbnail_size);
100     }
101 
102     videoThumbnailer.setWorkAroundIssues(thumbnailer->workaround_bugs != 0);
103     videoThumbnailer.setImageQuality(thumbnailer->thumbnail_image_quality);
104     videoThumbnailer.setMaintainAspectRatio(thumbnailer->maintain_aspect_ratio != 0);
105     videoThumbnailer.setPreferEmbeddedMetadata(thumbnailer->prefer_embedded_metadata != 0);
106 
107     if (thumbnailer->overlay_film_strip)
108     {
109         videoThumbnailer.removeFilter(&thumbnailer->tdata->filter);
110         videoThumbnailer.addFilter(&thumbnailer->tdata->filter);
111     }
112 
113     if (thumbnailer->seek_time != nullptr)
114     {
115         videoThumbnailer.setSeekTime(thumbnailer->seek_time);
116     }
117     else
118     {
119         videoThumbnailer.setSeekPercentage(thumbnailer->seek_percentage);
120     }
121 }
122 
video_thumbnailer_generate_thumbnail_to_buffer(video_thumbnailer * thumbnailer,const char * movie_filename,image_data * generated_image_data)123 extern "C" int video_thumbnailer_generate_thumbnail_to_buffer(video_thumbnailer* thumbnailer, const char* movie_filename, image_data* generated_image_data)
124 {
125     try
126     {
127         auto dataVector         = reinterpret_cast<std::vector<uint8_t>*>(generated_image_data->internal_data);
128         auto& videoThumbnailer  = thumbnailer->tdata->thumbnailer;
129         setProperties(thumbnailer);
130         auto info = videoThumbnailer.generateThumbnail(movie_filename, thumbnailer->thumbnail_image_type, *dataVector, thumbnailer->av_format_context);
131         generated_image_data->image_data_ptr = &dataVector->front();
132         generated_image_data->image_data_size = static_cast<int>(dataVector->size());
133         generated_image_data->image_data_width = info.width;
134         generated_image_data->image_data_height = info.height;
135         generated_image_data->image_data_source = info.source;
136     }
137     catch (const std::exception& e)
138     {
139         trace_message(thumbnailer, ThumbnailerLogLevelError, e.what());
140         return -1;
141     }
142 
143     return 0;
144 }
145 
video_thumbnailer_generate_thumbnail_to_file(video_thumbnailer * thumbnailer,const char * movie_filename,const char * output_fileName)146 extern "C" int video_thumbnailer_generate_thumbnail_to_file(video_thumbnailer* thumbnailer, const char* movie_filename, const char* output_fileName)
147 {
148     try
149     {
150         auto& videoThumbnailer = thumbnailer->tdata->thumbnailer;
151         setProperties(thumbnailer);
152         videoThumbnailer.generateThumbnail(movie_filename, thumbnailer->thumbnail_image_type, output_fileName, thumbnailer->av_format_context);
153     }
154     catch (const std::exception& e)
155     {
156         trace_message(thumbnailer, ThumbnailerLogLevelError, e.what());
157         return -1;
158     }
159 
160     return 0;
161 }
162 
video_thumbnailer_set_log_callback(video_thumbnailer * thumbnailer,thumbnailer_log_callback cb)163 extern "C" void video_thumbnailer_set_log_callback(video_thumbnailer* thumbnailer, thumbnailer_log_callback cb)
164 {
165     thumbnailer->tdata->log_cb = cb;
166     auto& videoThumbnailer = thumbnailer->tdata->thumbnailer;
167 
168     if (!cb)
169     {
170         videoThumbnailer.setLogCallback(nullptr);
171     }
172     else
173     {
174         videoThumbnailer.setLogCallback([=] (ThumbnailerLogLevel lvl, const std::string& msg) {
175             cb(lvl, msg.c_str());
176         });
177     }
178 }
179 
video_thumbnailer_set_size(video_thumbnailer * thumbnailer,int width,int height)180 extern "C" int video_thumbnailer_set_size(video_thumbnailer* thumbnailer, int width, int height)
181 {
182     auto& videoThumbnailer = thumbnailer->tdata->thumbnailer;
183 
184     try
185     {
186         thumbnailer->thumbnail_size = -1;
187         videoThumbnailer.setThumbnailSize(width, height);
188         return 0;
189     }
190     catch (const std::exception& e)
191     {
192         trace_message(thumbnailer, ThumbnailerLogLevelError, e.what());
193         return -1;
194     }
195 }
196