|
1 |
|
2 #include <gst/gst_global.h> |
|
3 #include <stdlib.h> |
|
4 #include <gst/gst.h> |
|
5 #include <gst/gstelement.h> |
|
6 #include <string.h> |
|
7 #define LOG_FILE "c:\\logs\\launch_logs.txt" |
|
8 #include "std_log_result.h" |
|
9 #define LOG_FILENAME_LINE __FILE__, __LINE__ |
|
10 |
|
11 static guint _bitrate = 128000; |
|
12 static guint _channels = 1; |
|
13 static guint _sample_rate = 8000; |
|
14 static guint _aac_profile = 2; // default is LC |
|
15 static guint _enable_logs = 1; |
|
16 static guint _record_duration = 10000; // recording duration |
|
17 #define REC_FILENAME_LEN 256 |
|
18 static char rec_filename[REC_FILENAME_LEN]; |
|
19 |
|
20 GstElement *pipeline; |
|
21 |
|
22 #define ENABLE_LOGS |
|
23 |
|
24 #ifdef ENABLE_LOGS |
|
25 #define RET_GST_ERR_STR(var, level, str) \ |
|
26 if ( level == var )\ |
|
27 return str; |
|
28 |
|
29 static inline const char* _gst_err_cat( GstDebugLevel level) |
|
30 { |
|
31 |
|
32 RET_GST_ERR_STR(level,GST_LEVEL_NONE,""); |
|
33 RET_GST_ERR_STR(level,GST_LEVEL_ERROR,"E "); |
|
34 RET_GST_ERR_STR(level,GST_LEVEL_WARNING,"W "); |
|
35 RET_GST_ERR_STR(level,GST_LEVEL_INFO,"I "); |
|
36 RET_GST_ERR_STR(level,GST_LEVEL_DEBUG,"D "); |
|
37 RET_GST_ERR_STR(level,GST_LEVEL_LOG, "L "); |
|
38 RET_GST_ERR_STR(level,GST_LEVEL_FIXME, "F "); |
|
39 RET_GST_ERR_STR(level,GST_LEVEL_MEMDUMP, "M "); |
|
40 return ""; |
|
41 } |
|
42 static inline const char* _str_aac_profile() |
|
43 { |
|
44 if ( _aac_profile == 0) return "auto"; |
|
45 if ( _aac_profile == 2) return "lc"; |
|
46 if ( _aac_profile == 5) return "he"; |
|
47 return "unknown"; |
|
48 } |
|
49 |
|
50 static FILE* log_fp = 0; |
|
51 |
|
52 static void open_log_fp() |
|
53 { |
|
54 if (!log_fp) |
|
55 { |
|
56 snprintf(rec_filename, REC_FILENAME_LEN, "C://Data//gst_br%d_c%d_sr%d_%s.log", _bitrate, _channels, _sample_rate, _str_aac_profile()); |
|
57 |
|
58 log_fp = fopen(rec_filename, "w"); |
|
59 if (!log_fp) |
|
60 return; |
|
61 } |
|
62 } |
|
63 |
|
64 |
|
65 static void _gstLogFunction (GstDebugCategory *category, |
|
66 GstDebugLevel level, |
|
67 const gchar *file, |
|
68 const gchar *function, |
|
69 gint line, |
|
70 GObject *object, |
|
71 GstDebugMessage *message, |
|
72 gpointer data) |
|
73 { |
|
74 |
|
75 // if ( (level != GST_LEVEL_ERROR) /*&& (level != GST_LEVEL_DEBUG)*/ && (level != GST_LEVEL_WARNING) ) |
|
76 // return; |
|
77 |
|
78 open_log_fp(); |
|
79 |
|
80 fprintf(log_fp, "%s : %s \n", _gst_err_cat(level), gst_debug_message_get(message)); |
|
81 fflush(log_fp); |
|
82 |
|
83 } |
|
84 #endif // ENABLE_LOGS |
|
85 |
|
86 // Local Functions |
|
87 static gboolean |
|
88 bus_call (GstBus *bus, |
|
89 GstMessage *msg, |
|
90 gpointer data) |
|
91 { |
|
92 |
|
93 GMainLoop *loop = (GMainLoop *) data; |
|
94 |
|
95 open_log_fp(); |
|
96 |
|
97 fprintf(log_fp,"[msg] %s from %s\n", GST_MESSAGE_TYPE_NAME(msg), GST_MESSAGE_SRC_NAME (msg)); |
|
98 |
|
99 switch (GST_MESSAGE_TYPE (msg)) { |
|
100 case GST_MESSAGE_EOS: |
|
101 gst_element_set_state (pipeline, GST_STATE_NULL); |
|
102 gst_object_unref (GST_OBJECT (pipeline)); |
|
103 g_main_loop_quit(loop); |
|
104 break; |
|
105 case GST_MESSAGE_ERROR: { |
|
106 gchar *debug; |
|
107 GError *err; |
|
108 gst_message_parse_error (msg, &err, &debug); |
|
109 fprintf(log_fp, "[ERROR] %s\n", debug); |
|
110 g_free (debug); |
|
111 g_error_free (err); |
|
112 g_main_loop_quit(loop); |
|
113 break; |
|
114 } |
|
115 #if 0 |
|
116 case GST_MESSAGE_STATE_CHANGED: |
|
117 { |
|
118 GstState state; |
|
119 // gst_element_get_state (GstElement * element, |
|
120 // GstState * state, |
|
121 // GstState * pending, |
|
122 // GstClockTime timeout); |
|
123 |
|
124 gst_element_get_state(GST_ELEMENT(pipeline),&state,NULL,-1); |
|
125 if(state == GST_STATE_PLAYING) |
|
126 { |
|
127 |
|
128 } |
|
129 |
|
130 } |
|
131 break; |
|
132 #endif |
|
133 default: |
|
134 break; |
|
135 } |
|
136 |
|
137 return TRUE; |
|
138 } |
|
139 |
|
140 static gboolean |
|
141 quit_loop (gpointer data) |
|
142 { |
|
143 GST_DEBUG("quiting loop"); |
|
144 gst_element_send_event (pipeline, gst_event_new_eos ()); |
|
145 return TRUE; |
|
146 } |
|
147 |
|
148 |
|
149 static void parse_args(int argc, char** argv) |
|
150 { |
|
151 |
|
152 gint cur = 1; |
|
153 while ( argv[cur] && cur < argc ) |
|
154 { |
|
155 if( !strcmp(argv[cur],"-br") ) _bitrate = atoi(argv[cur+1]); |
|
156 else if( !strcmp(argv[cur],"-c") ) _channels = atoi(argv[cur+1]); |
|
157 else if( !strcmp(argv[cur],"-sr") ) _sample_rate = atoi(argv[cur+1]); |
|
158 else if( !strcmp(argv[cur],"-p") ) _aac_profile = atoi(argv[cur+1]); |
|
159 else if( !strcmp(argv[cur],"-l") ) _enable_logs = atoi(argv[cur+1]); |
|
160 else if( !strcmp(argv[cur],"-d") ) _record_duration = atoi(argv[cur+1]); |
|
161 |
|
162 cur+=2; |
|
163 } |
|
164 } |
|
165 |
|
166 // Currently unused, TODO merge all recording usecases in this app. |
|
167 #if 0 |
|
168 char gst_pipeline[4096]; |
|
169 |
|
170 static inline GstElement* __parse_wav_pipeline() |
|
171 { |
|
172 snprintf(gst_pipeline, 4096, "devsoundsrc ! audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)%d, channels=(int)%d, endianness=(int)1234 ! wavenc ! filesink location=C://Data//wav_c%d_sr%d.wav", |
|
173 _sample_rate, _channels , _channels, _sample_rate ); |
|
174 pipeline = gst_parse_launch( gst_pipeline,0); |
|
175 return pipeline; |
|
176 } |
|
177 static inline GstElement* __get_wav_pipeline() |
|
178 { |
|
179 GstCaps* caps; |
|
180 GstElement *devsoundsrc,*filesink,*wavenc; |
|
181 GError *error = NULL; |
|
182 |
|
183 pipeline = gst_pipeline_new ("pipeline"); |
|
184 devsoundsrc = gst_element_factory_make ("devsoundsrc", "devsoundsrc"); |
|
185 wavenc = gst_element_factory_make ("wavenc", "wavenc"); |
|
186 filesink = gst_element_factory_make ("filesink", "filesink"); |
|
187 |
|
188 snprintf(rec_filename, REC_FILENAME_LEN, "C:\\\\data\\\\wav_c%d_sr%d.wav", _channels, _sample_rate); |
|
189 g_object_set (G_OBJECT (filesink), "location", rec_filename, NULL); |
|
190 |
|
191 |
|
192 GST_DEBUG("filtered linking..."); |
|
193 |
|
194 caps = gst_caps_new_simple ("audio/x-raw-int", |
|
195 "width", G_TYPE_INT, 16, |
|
196 "depth", G_TYPE_INT, 16, |
|
197 "signed",G_TYPE_BOOLEAN, TRUE, |
|
198 "endianness",G_TYPE_INT, G_BYTE_ORDER, |
|
199 "rate", G_TYPE_INT, _sample_rate, |
|
200 "channels", G_TYPE_INT, _channels, NULL); |
|
201 |
|
202 gst_bin_add_many (GST_BIN (pipeline), devsoundsrc, wavenc, filesink, NULL); |
|
203 gst_element_link_filtered (devsoundsrc, wavenc, caps); |
|
204 |
|
205 |
|
206 gst_element_link (wavenc, filesink); |
|
207 gst_caps_unref (caps); |
|
208 |
|
209 return pipeline; |
|
210 |
|
211 } |
|
212 #endif |
|
213 |
|
214 static inline GstElement* __get_aac_pipeline() |
|
215 { |
|
216 GstCaps* caps; |
|
217 GstElement *devsoundsrc,*filesink,*nokiaaacenc,*mp4mux; |
|
218 GstPad *qtsinkpad,*aacencsrcpad; |
|
219 |
|
220 pipeline = gst_pipeline_new ("pipeline"); |
|
221 devsoundsrc = gst_element_factory_make ("devsoundsrc", "devsoundsrc"); |
|
222 nokiaaacenc = gst_element_factory_make ("nokiaaacenc", "nokiaaacenc"); |
|
223 mp4mux = gst_element_factory_make ("mp4mux", "mp4mux"); |
|
224 filesink = gst_element_factory_make ("filesink", "filesink"); |
|
225 |
|
226 snprintf(rec_filename, REC_FILENAME_LEN, "C:\\\\data\\\\rec-aac_br%d_c%d_sr%d_%s.mp4", _bitrate, _channels, _sample_rate, |
|
227 _str_aac_profile()); |
|
228 g_object_set (G_OBJECT (filesink), "location", rec_filename, NULL); |
|
229 |
|
230 //GST_DEBUG("set bitrate on aacenc"); |
|
231 g_object_set (G_OBJECT (nokiaaacenc), "bitrate", _bitrate, NULL); |
|
232 |
|
233 //if ( _aac_profile ) |
|
234 g_object_set (G_OBJECT (nokiaaacenc), "profile", _aac_profile, NULL); |
|
235 |
|
236 |
|
237 GST_DEBUG("filtered linking..."); |
|
238 |
|
239 caps = gst_caps_new_simple ("audio/x-raw-int", |
|
240 "width", G_TYPE_INT, 16, |
|
241 "depth", G_TYPE_INT, 16, |
|
242 "signed",G_TYPE_BOOLEAN, TRUE, |
|
243 "endianness",G_TYPE_INT, G_BYTE_ORDER, |
|
244 "rate", G_TYPE_INT, _sample_rate, |
|
245 "channels", G_TYPE_INT, _channels, NULL); |
|
246 |
|
247 gst_bin_add_many (GST_BIN (pipeline), devsoundsrc, nokiaaacenc, mp4mux, filesink, NULL); |
|
248 gst_element_link_filtered (devsoundsrc, nokiaaacenc, caps); |
|
249 |
|
250 qtsinkpad = gst_element_get_request_pad( mp4mux, "audio_%d"); |
|
251 aacencsrcpad = gst_element_get_pad( nokiaaacenc, "src"); |
|
252 if (gst_pad_link (aacencsrcpad,qtsinkpad) != GST_PAD_LINK_OK) { |
|
253 |
|
254 GST_ERROR("gst_pad_link (aacencsrcpad,qtsinkpad) failed"); |
|
255 return NULL; |
|
256 } |
|
257 gst_element_link (mp4mux, filesink); |
|
258 gst_caps_unref (caps); |
|
259 |
|
260 return pipeline; |
|
261 } |
|
262 |
|
263 int main (int argc, char *argv[]) |
|
264 { |
|
265 GMainLoop *loop; |
|
266 |
|
267 |
|
268 #ifdef ENABLE_LOGS |
|
269 if ( _enable_logs ) |
|
270 setenv("GST_DEBUG","2",1); |
|
271 #endif // ENABLE_LOGS |
|
272 |
|
273 gst_init (NULL, NULL); |
|
274 |
|
275 parse_args(argc, argv); |
|
276 |
|
277 #ifdef ENABLE_LOGS |
|
278 if ( _enable_logs ) |
|
279 gst_debug_add_log_function( _gstLogFunction, 0); |
|
280 #endif // ENABLE_LOGS |
|
281 |
|
282 GST_DEBUG("args : br %d chans %d sr %d ", _bitrate, _channels, _sample_rate); |
|
283 |
|
284 loop = g_main_loop_new (NULL, FALSE); |
|
285 |
|
286 |
|
287 //pipeline = __get_wav_pipeline(); |
|
288 //pipeline = __parse_wav_pipeline(); |
|
289 pipeline = __get_aac_pipeline(); |
|
290 |
|
291 |
|
292 /* start playing */ |
|
293 gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), bus_call, loop); |
|
294 // watchdog timer |
|
295 //g_timeout_add (_record_duration * 1.5, quit_program, 0); |
|
296 |
|
297 gst_element_set_state (pipeline, GST_STATE_PLAYING); |
|
298 |
|
299 g_timeout_add (_record_duration, quit_loop, loop); |
|
300 |
|
301 |
|
302 g_main_loop_run (loop); |
|
303 |
|
304 gst_element_set_state (pipeline, GST_STATE_NULL); |
|
305 gst_object_unref (GST_OBJECT (pipeline)); |
|
306 |
|
307 #ifdef ENABLE_LOGS |
|
308 if ( _enable_logs ) |
|
309 fclose(log_fp); |
|
310 #endif // ENABLE_LOGS |
|
311 } |
|
312 |
|
313 |