[M47_2526] Chromium upversion to m47_2526 branch
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / content / browser / media / efl / webaudio_decoder_browser_gstreamer.cc
1 // Copyright 2014 Samsung Electronics Inc. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/media/efl/webaudio_decoder_browser_gstreamer.h"
6
7 #include <gst/app/gstappsink.h>
8 #include <gst/app/gstappsrc.h>
9 #include <gst/audio/audio.h>
10 #include <gst/gst.h>
11
12 #include "base/bind.h"
13 #include "base/strings/string_util.h"
14 #include "base/time/time.h"
15 #include "media/base/audio_bus.h"
16 #include "media/base/limits.h"
17 #include "media/base/efl/webaudio_media_codec_info_efl.h"
18 #include "third_party/WebKit/public/platform/WebAudioBus.h"
19
20 namespace content {
21
22 #define CHUNK_SIZE 204800  // (4096*50)
23 #define GST_OBJECT_UNREF(obj) \
24     if (obj) { \
25       gst_object_unref(obj); \
26       obj = NULL; \
27     }
28
29 static int gst_dec_count_ = 32;
30 static int audio_width_ = 16;
31
32 struct GstElementDeleter {
33   void operator()(GstElement* ptr) const {
34     GST_OBJECT_UNREF(ptr);
35   }
36 };
37
38 // GSTDecoder class - declaration
39 class GSTDecoder {
40  public:
41   GSTDecoder(uint8_t* data, int pcm_output, uint32_t data_size);
42   ~GSTDecoder();
43   void InitializeGstDestination(int pcm_output,
44                                 uint16_t number_of_channels,
45                                 uint32_t sample_rate,
46                                 size_t number_of_frames);
47   void SendGstOutputUsinghandle(int pcm_output, uint8_t* buffer, int buf_size);
48   void MediaFileDecoder();
49
50   // callbacks
51   static void OnNewPadAdded(GstElement* bin, GstPad* pad,
52                             gpointer user_data);
53   static void OnNeedData(GstElement* source, guint size, gpointer user_data);
54   static void OnEOS(GstAppSink* sink, gpointer user_data);
55   static GstFlowReturn OnNewPreroll(GstAppSink* sink, gpointer user_data);
56   static GstFlowReturn OnNewBuffer(GstAppSink* sink, gpointer user_data);
57   static GstBusSyncReply OnBusMessage(GstBus* bus, GstMessage* message,
58                                       gpointer user_data);
59  private:
60   GstElement* app_src_;
61   GstElement* audioconvert_;
62   guint8* encodeddata_;
63   gsize enc_length_;
64   guint64 enc_offset_;
65   int pcm_output_;
66   bool is_running_;
67   bool is_endofstream_;
68   bool is_new_request_;
69 };  // GSTDecoder class
70
71 GSTDecoder::GSTDecoder(uint8_t* data, int pcm_output, uint32_t data_size)
72   : app_src_(NULL),
73     audioconvert_(NULL),
74     encodeddata_(data),
75     enc_length_(data_size),
76     enc_offset_(0),
77     pcm_output_(pcm_output),
78     is_running_(true),
79     is_endofstream_(false),
80     is_new_request_(true) {
81   DCHECK(encodeddata_);
82 }
83
84 GSTDecoder::~GSTDecoder() {
85   delete encodeddata_;
86   encodeddata_ = NULL;
87 }
88
89 void GSTDecoder::InitializeGstDestination(int pcm_output,
90                                           uint16_t number_of_channels,
91                                           uint32_t sample_rate,
92                                           size_t number_of_frames) {
93   struct media::WebAudioMediaCodecInfoEfl info = {
94       static_cast<unsigned long>(number_of_channels),
95       static_cast<unsigned long>(sample_rate),
96       static_cast<unsigned long>(number_of_frames)
97   };
98
99   HANDLE_EINTR(write(pcm_output, &info, sizeof(info)));
100 }
101
102 void GSTDecoder::SendGstOutputUsinghandle(int pcm_output, uint8_t* buffer,
103                                           int buf_size) {
104   size_t count = buf_size;
105   while (count > 0) {
106     int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count;
107     ssize_t bytes_written =
108         HANDLE_EINTR(write(pcm_output, buffer, bytes_to_write));
109     if (bytes_written == -1)
110       break;
111     count -= bytes_written;
112     buffer += bytes_written;
113   }
114   return;
115 }
116
117 void GSTDecoder::MediaFileDecoder() {
118   if (!gst_is_initialized()) {
119     GError* err = NULL;
120     if (!gst_init_check(NULL, NULL, &err)) {
121       LOG(ERROR) << "Gst could not be initialized";
122       close(pcm_output_);
123       return;
124     }
125   }
126
127   scoped_ptr<GstElement, GstElementDeleter> pipeline;
128   gchar pipeline_name[16] = {0,};
129   sprintf(pipeline_name, "pipeline_%d", gst_dec_count_);
130
131   // makes gst-pipeline
132   pipeline.reset(gst_pipeline_new((const gchar*)&pipeline_name));
133   GstBus* bus = NULL;
134   if (!(bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline.get())))) {
135     LOG(ERROR) << "GStreamer bus creation failed";
136     return;
137   }
138   gst_bus_set_sync_handler(
139       bus, (GstBusSyncHandler)OnBusMessage, this, NULL);
140
141   // App Src init
142   app_src_ = gst_element_factory_make("appsrc", NULL);
143   if (!gst_bin_add(GST_BIN(pipeline.get()), app_src_)) {
144     GST_OBJECT_UNREF(app_src_);
145     return;
146   }
147   g_signal_connect(app_src_, "need-data", G_CALLBACK(OnNeedData), this);
148
149   // App Sink init
150   GstElement* app_sink = gst_element_factory_make("appsink", NULL);
151   if (!gst_bin_add(GST_BIN(pipeline.get()), app_sink)) {
152     GST_OBJECT_UNREF(app_sink);
153     return;
154   }
155   GstAppSinkCallbacks callbacks = {OnEOS, OnNewPreroll, OnNewBuffer};
156   gst_app_sink_set_callbacks(GST_APP_SINK(app_sink), &callbacks, this, NULL);
157   g_object_set(G_OBJECT(app_sink), "sync", FALSE, NULL);
158
159   // Decoder init
160   GstElement* decoder = gst_element_factory_make("decodebin", NULL);
161   if (!gst_bin_add(GST_BIN(pipeline.get()), decoder)) {
162     GST_OBJECT_UNREF(decoder);
163     return;
164   }
165   g_signal_connect(decoder, "pad-added", G_CALLBACK(OnNewPadAdded), this);
166
167   // audio converter init
168   audioconvert_ = gst_element_factory_make("audioconvert", NULL);
169   if (!gst_bin_add(GST_BIN(pipeline.get()), audioconvert_)) {
170     GST_OBJECT_UNREF(audioconvert_);
171     return;
172   }
173
174   // Resample init
175   GstElement* sampler = gst_element_factory_make("audioresample", NULL);
176   if (!gst_bin_add(GST_BIN(pipeline.get()), sampler)) {
177     GST_OBJECT_UNREF(sampler);
178     return;
179   }
180
181   // Capsfilter init
182   GstElement* capsfilter = gst_element_factory_make("capsfilter", NULL);
183   if (!gst_bin_add(GST_BIN(pipeline.get()), capsfilter)) {
184     GST_OBJECT_UNREF(capsfilter);
185     return;
186   }
187
188   GstCaps* caps = gst_caps_new_simple("audio/x-raw",
189                                       "format", G_TYPE_STRING, "S16LE",
190                                       "rate", G_TYPE_INT, 44100,
191                                       "channels", G_TYPE_INT, 2,
192                                       "layout", G_TYPE_STRING, "interleaved",
193                                       NULL);
194
195   g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
196   gst_caps_unref(caps);
197
198   gst_dec_count_++;
199   if (gst_dec_count_ > 126)
200     gst_dec_count_ = 32;
201
202   if (!gst_element_link(app_src_, decoder)) {
203     LOG(ERROR) << " Something wrong on gst initialization";
204     return;
205   }
206
207   if (!gst_element_link_many(audioconvert_, sampler,
208       capsfilter, app_sink, NULL)) {
209     LOG(ERROR) << "Some element could not be linked";
210     return;
211   }
212
213   // actually works decoding
214   gst_element_set_state(pipeline.get(), GST_STATE_PLAYING);
215
216   //FIXME: Check if its possible to remove usleep() and make any gst
217   //async call so that GST wont block on Browser UI thread.
218   while (is_running_) {
219     usleep(10);
220   }
221
222   // returns resource(s)
223   g_signal_handlers_disconnect_by_func(
224       bus, reinterpret_cast<gpointer>(OnBusMessage), this);
225   gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
226   GST_OBJECT_UNREF(bus);
227   gst_element_set_state(pipeline.get(), GST_STATE_NULL);
228 }
229
230 void GSTDecoder::OnNewPadAdded(GstElement* /*bin*/, GstPad* pad,
231                                gpointer data) {
232   GSTDecoder* decoder = static_cast<GSTDecoder*>(data);
233   GstPad* sink_pad = gst_element_get_static_pad(decoder->audioconvert_, "sink");
234   if (!GST_PAD_IS_LINKED(sink_pad)) {
235     gst_pad_link(pad, sink_pad);
236   }
237   g_object_unref(sink_pad);
238 }
239
240 void GSTDecoder::OnNeedData(GstElement* /*source*/, guint /*size*/,
241                             gpointer data) {
242   GSTDecoder* decoder = static_cast<GSTDecoder*>(data);
243   if (decoder->is_endofstream_)
244     return;
245
246   guint len = CHUNK_SIZE;
247   if ((decoder->enc_offset_ + len ) > decoder->enc_length_)
248     len = decoder->enc_length_ - decoder->enc_offset_;
249
250   GstBuffer* buffer =
251       gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY,
252                                   decoder->encodeddata_ + decoder->enc_offset_,
253                                   len, 0, len, NULL, NULL);
254   if (!buffer) {
255     LOG(ERROR) << "OnNeedData: buffer creation: FAILED";
256     return;
257   }
258   decoder->enc_offset_ += len;
259
260   GstFlowReturn ret = GST_FLOW_OK;
261   g_signal_emit_by_name(decoder->app_src_, "push-buffer", buffer, &ret);
262
263   if (ret != GST_FLOW_OK) {
264     LOG(ERROR) << "OnNeedData: push-buffer ret: FAILED";
265     decoder->is_running_ = false;
266   }
267
268   if (decoder->enc_offset_ >= decoder->enc_length_) {
269     decoder->is_endofstream_ = TRUE;
270     g_signal_emit_by_name(decoder->app_src_, "end-of-stream", &ret);
271   }
272   gst_buffer_unref(buffer);
273 }
274
275 void GSTDecoder::OnEOS(GstAppSink* sink, gpointer data) {
276   GSTDecoder* decoder = static_cast<GSTDecoder*>(data);
277   if (!decoder->is_endofstream_) {
278     LOG(ERROR) << "not end of stream yet appsrc-side";
279   }
280
281   close(decoder->pcm_output_);
282   decoder->is_running_ = false;
283 }
284
285 GstFlowReturn GSTDecoder::OnNewPreroll(GstAppSink*, gpointer) {
286   return GST_FLOW_OK;
287 }
288
289 GstFlowReturn GSTDecoder::OnNewBuffer(GstAppSink* sink, gpointer data) {
290   GSTDecoder* decoder = static_cast<GSTDecoder*>(data);
291   GstSample* sample = gst_app_sink_pull_sample(sink);
292   if (!sample)
293     return GST_FLOW_ERROR;
294
295   GstBuffer* buffer = gst_sample_get_buffer(sample);
296
297   if (!buffer) {
298     gst_sample_unref(sample);
299     return GST_FLOW_ERROR;
300   }
301
302   if (decoder->is_new_request_) {
303     GstCaps* caps = NULL;
304     GstStructure* str = NULL;
305     gboolean ret = true;
306     gint channel = 0;
307     gint rate = 0;
308     caps = gst_sample_get_caps(sample);
309     str = gst_caps_get_structure(caps, 0);
310     if (!caps || !str) {
311       gst_sample_unref(sample);
312       return GST_FLOW_ERROR;
313     }
314     ret &= gst_structure_get_int(str, "channels", &channel);
315     ret &= gst_structure_get_int(str, "rate", &rate);
316
317     if (!ret || !channel || !rate) {
318       gst_sample_unref(sample);
319       return GST_FLOW_ERROR;
320     }
321
322     GstClockTime duration =
323         (static_cast<guint64>(gst_buffer_get_size(buffer)) * 8 * GST_SECOND) /
324         (channel * rate * audio_width_);
325     int frames = GST_CLOCK_TIME_TO_FRAMES(duration, rate);
326
327     decoder->InitializeGstDestination(decoder->pcm_output_, channel,
328                                       rate, frames);
329     decoder->is_new_request_ = false;
330   }
331
332   GstMapInfo gst_map;
333   gst_buffer_map(buffer, &gst_map, static_cast<GstMapFlags>(GST_MAP_READ));
334   if (gst_map.size > 0) {
335     decoder->SendGstOutputUsinghandle(decoder->pcm_output_,
336                                       gst_map.data,
337                                       gst_map.size);
338     gst_buffer_unmap(buffer, &gst_map);
339   }
340
341   gst_sample_unref(sample);
342   return GST_FLOW_OK;
343 }
344
345 GstBusSyncReply GSTDecoder::OnBusMessage(GstBus* bus,
346                                          GstMessage* message,
347                                          gpointer data) {
348   GSTDecoder* decoder = static_cast<GSTDecoder*>(data);
349   switch (GST_MESSAGE_TYPE(message)) {
350     case GST_MESSAGE_ERROR:
351       GError* error;
352       gst_message_parse_error(message, &error, NULL);
353       LOG(ERROR) << "Error message : " << error->message
354           << " recieved from : "<< GST_MESSAGE_SRC_NAME(message)
355           << ", error code : " << error->code;
356       g_error_free(error);
357
358       if (decoder->is_running_) {
359         close(decoder->pcm_output_);
360         decoder->is_running_ = false;
361       }
362       break;
363     default:
364       DVLOG(1) << "Unhandled GStreamer message type : "
365                << GST_MESSAGE_TYPE_NAME(message);
366       break;
367   }
368   gst_message_unref(message);
369   return GST_BUS_DROP;
370 }
371
372 // WebAudioDecoderGStreamer class
373
374 // static
375 WebAudioDecoderGStreamer* WebAudioDecoderGStreamer::GetInstance() {
376   return base::Singleton<WebAudioDecoderGStreamer>::get();
377 }
378
379 WebAudioDecoderGStreamer::WebAudioDecoderGStreamer()
380     : gst_thread_("GstThread") {
381 }
382
383 WebAudioDecoderGStreamer::~WebAudioDecoderGStreamer() {
384 }
385
386 void WebAudioDecoderGStreamer::DecodeUsingGST(
387     base::SharedMemoryHandle foreign_memory_handle,
388     base::FileDescriptor pcm_output,
389     uint32_t data_size) {
390
391   base::SharedMemory shared_memory(foreign_memory_handle, false);
392   if (!shared_memory.Map(data_size)) {
393     LOG(ERROR) << "Failed to map shared memory for size " << data_size;
394     return;
395   }
396
397   uint8_t* encoded_data = new uint8_t[data_size];
398   if (!encoded_data) {
399     LOG(ERROR) << "Memory allocation failed for size = " << data_size;
400     return;
401   }
402
403   memcpy(encoded_data,
404          static_cast<uint8_t*>(shared_memory.memory()),
405          data_size);
406
407   // This will execute until decoding is done
408   GSTDecoder decoder(encoded_data, pcm_output.fd, data_size);
409   decoder.MediaFileDecoder();
410 }
411
412 void WebAudioDecoderGStreamer::EncodedDataReceived(
413     base::SharedMemoryHandle foreign_memory_handle,
414     base::FileDescriptor pcm_output,
415     uint32_t data_size) {
416
417   if (!gst_thread_.IsRunning() && !gst_thread_.Start()) {
418     LOG(ERROR) << "Starting GStreamer thread failed";
419     return;
420   }
421
422   gst_thread_.message_loop()->PostTask(FROM_HERE,
423       base::Bind(&WebAudioDecoderGStreamer::DecodeUsingGST,
424       base::Unretained(this), foreign_memory_handle,
425       pcm_output, data_size));
426 }
427
428 }  // namespace content