diff --git a/.vscode/settings.json b/.vscode/settings.json index ef735b9..5944255 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "files.associations": { - "gst.h": "c" + "gst.h": "c", + "audio.h": "c" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index aea9ad7..bf814a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,12 @@ include_directories(/usr/lib/aarch64-linux-gnu/glib-2.0/include) # add_executable(${PROJECT_NAME} basic-tutorial-2.c) # add_executable(${PROJECT_NAME} basic-tutorial-3.c) # add_executable(${PROJECT_NAME} basic-tutorial-6.c) -add_executable(${PROJECT_NAME} basic-tutorial-7.c) +# add_executable(${PROJECT_NAME} basic-tutorial-7.c) +add_executable(${PROJECT_NAME} basic-tutorial-8.c) target_link_libraries(${PROJECT_NAME} gstreamer-1.0 gobject-2.0 glib-2.0 +gstaudio-1.0 ) \ No newline at end of file diff --git a/basic-tutorial-8.c b/basic-tutorial-8.c new file mode 100644 index 0000000..816ab75 --- /dev/null +++ b/basic-tutorial-8.c @@ -0,0 +1,215 @@ +#include +#include +#include + +#define CHUNK_SIZE 1024 +#define SAMPLE_RATE 44100 + +typedef struct _CustomData +{ + GstElement *pipeline,*app_source,*tee,*audio_queue,*audio_convert1,*audio_resample,*audio_sink; + GstElement *video_queue,*audio_convert2,*visual,*video_convert,*video_sink; + GstElement *app_queue,*app_sink; + + guint64 num_samples; + gfloat a,b,c,d; + + guint sourceid; + + GMainLoop *main_loop; +}CustomData; + +static gboolean push_data(CustomData *data) +{ + GstBuffer *buffer; + GstFlowReturn ret; + int i; + GstMapInfo map; + gint16 *raw; + gint num_samples = CHUNK_SIZE / 2; + gfloat freq; + + buffer = gst_buffer_new_and_alloc (CHUNK_SIZE); + + GST_BUFFER_TIMESTAMP(buffer) = gst_util_uint64_scale(data->num_samples,GST_SECOND,SAMPLE_RATE); + GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale(num_samples,GST_SECOND,SAMPLE_RATE); + + gst_buffer_map(buffer, &map,GST_MAP_WRITE); + raw = (gint16 *)map.data; + data->c +=data->d; + data->d -=data->c /1000; + freq = 1100 + 1000 * data->d; + for(i = 0;ia +=data->b; + data->b -=data->a / freq; + raw[i] = (gint16)(500 * data->a ); + } + gst_buffer_unmap(buffer, &map); + data->num_samples += num_samples; + + g_signal_emit_by_name(data->app_source,"push-buffer",buffer,&ret); + + gst_buffer_unref(buffer); + + if(ret != GST_FLOW_OK) + { + return FALSE; + } + return TRUE; +} + +static void start_feed(GstElement *source, guint size, CustomData *data) +{ + if(data->sourceid == 0) + { + g_print("Start feeding\n"); + data->sourceid = g_idle_add((GSourceFunc) push_data,data); + } +} + +static void stop_feed(GstElement *source,CustomData *data) +{ + if(data->sourceid != 0) + { + g_print("Stop feeding\n"); + g_source_remove(data->sourceid); + data->sourceid = 0; + } +} + +static GstFlowReturn new_sample(GstElement *sink,CustomData *data) +{ + GstSample *sample; + + g_signal_emit_by_name(sink,"pull-sample",&sample); + if(sample) + { + g_print("*"); + gst_sample_unref(sample); + return GST_FLOW_OK; + } + return GST_FLOW_ERROR; +} + +static void error_cb(GstBus *bus,GstMessage *msg,CustomData *data) +{ + GError *err; + gchar *debug_info; + + gst_message_parse_error(msg,&err,&debug_info); + g_printerr("Error received from element %s: %s\n",GST_OBJECT_NAME(msg->src),err->message); + g_printerr("Debugging information: %s\n",debug_info ? debug_info : "none"); + g_clear_error(&err); + g_free(debug_info); + + g_main_loop_quit(data->main_loop); +} + +int main(int argc, char *argv[]) +{ + CustomData data; + GstPad *tee_audio_pad,*tee_video_pad,*tee_app_pad; + GstPad *queue_audio_pad,*queue_video_pad,*queue_app_pad; + GstAudioInfo info; + GstCaps *audio_caps; + GstBus *bus; + + memset(&data,0,sizeof(data)); + data.b = 1; + data.d = 1; + + gst_init(&argc,&argv); + + data.app_source = gst_element_factory_make("appsrc","audio_source"); + data.tee = gst_element_factory_make("tee","tee"); + data.audio_queue = gst_element_factory_make("queue","audio_queue"); + data.audio_convert1 = gst_element_factory_make("audioconvert","audio_convert1"); + data.audio_resample = gst_element_factory_make("audioresample","audio_resample"); + data.audio_sink = gst_element_factory_make("autoaudiosink","audio_sink"); + data.video_queue = gst_element_factory_make("queue","video_queue"); + data.audio_convert2 = gst_element_factory_make("audioconvert","audio_convert2"); + data.visual = gst_element_factory_make("wavescope","visual"); + data.video_convert = gst_element_factory_make("videoconvert","video_convert"); + data.video_sink = gst_element_factory_make("autovideosink","video_sink"); + data.app_queue = gst_element_factory_make("queue","app_queue"); + data.app_sink = gst_element_factory_make("appsink","app_sink"); + + data.pipeline = gst_pipeline_new("test-pipeline"); + + if( !data.pipeline || !data.app_source || !data.tee || !data.audio_queue || !data.audio_convert1 || !data.audio_resample + || !data.audio_resample || !data.audio_sink || !data.video_queue || !data.audio_convert2 || !data.visual + || !data.video_convert || !data.video_sink || !data.app_queue || !data.app_sink) + { + g_printerr("Not all element could be created.\n"); + return -1; + } + + g_object_set (data.visual,"shader",0,"style",0,NULL); + + gst_audio_info_set_format(&info,GST_AUDIO_FORMAT_S16, SAMPLE_RATE,1,NULL); + audio_caps = gst_audio_info_to_caps(&info); + g_object_set(data.app_source,"caps",audio_caps,"format",GST_FORMAT_TIME,NULL); + g_signal_connect(data.app_source,"need-data",G_CALLBACK(start_feed),&data); + g_signal_connect(data.app_source,"enough-data",G_CALLBACK(stop_feed),&data); + + g_object_set(data.app_sink,"emit-signals",TRUE,"caps",audio_caps,NULL); + g_signal_connect(data.app_sink,"new-sample",G_CALLBACK(new_sample),&data); + gst_caps_unref(audio_caps); + + gst_bin_add_many(GST_BIN(data.pipeline),data.app_source,data.tee,data.audio_queue, + data.audio_convert1,data.audio_resample,data.audio_sink,data.video_queue, + data.audio_convert2,data.visual,data.video_convert,data.video_sink, + data.app_queue,data.app_sink,NULL); + if(gst_element_link_many (data.app_source,data.tee,NULL) != TRUE || + gst_element_link_many (data.audio_queue,data.audio_convert1,data.audio_resample,data.audio_sink,NULL) != TRUE || + gst_element_link_many (data.video_queue,data.audio_convert2,data.visual,data.video_convert,data.video_sink,NULL) != TRUE || + gst_element_link_many (data.app_queue,data.app_sink,NULL) != TRUE) + { + g_printerr("ELements could not be linked.\n"); + gst_object_unref(data.pipeline); + return -1; + } + + tee_audio_pad = gst_element_get_request_pad(data.tee,"src_%u"); + g_print("Obtained request pad %s for audio branch.\n",gst_pad_get_name(tee_audio_pad)); + queue_audio_pad = gst_element_get_static_pad(data.audio_queue,"sink"); + tee_video_pad = gst_element_get_request_pad(data.tee,"src_%u"); + g_print("Obtained request pad %s for video branch.\n",gst_pad_get_name(tee_video_pad)); + queue_video_pad = gst_element_get_static_pad(data.video_queue,"sink"); + tee_app_pad = gst_element_get_request_pad(data.tee,"src_%u"); + g_print("Obtained request pad %s for app branch.\n",gst_pad_get_name(tee_app_pad)); + queue_app_pad = gst_element_get_static_pad(data.app_queue,"sink"); + if(gst_pad_link(tee_audio_pad,queue_audio_pad) != GST_PAD_LINK_OK || + gst_pad_link(tee_video_pad,queue_video_pad) != GST_PAD_LINK_OK || + gst_pad_link(tee_app_pad,queue_app_pad) != GST_PAD_LINK_OK) + { + g_printerr("Tee could not be linked\n"); + return -1; + } + + gst_object_unref(queue_audio_pad); + gst_object_unref(queue_video_pad); + gst_object_unref(queue_app_pad); + + bus = gst_element_get_bus(data.pipeline); + gst_bus_add_signal_watch(bus); + g_signal_connect(G_OBJECT(bus),"message::error",(GCallback)error_cb,&data); + gst_object_unref(bus); + + gst_element_set_state(data.pipeline,GST_STATE_PLAYING); + + data.main_loop = g_main_loop_new(NULL,FALSE); + g_main_loop_run(data.main_loop); + + gst_element_release_request_pad(data.tee,tee_audio_pad); + gst_element_release_request_pad(data.tee,tee_video_pad); + gst_element_release_request_pad(data.tee,tee_app_pad); + gst_object_unref(tee_audio_pad); + gst_object_unref(tee_video_pad); + gst_object_unref(tee_app_pad); + + gst_element_set_state(data.pipeline,GST_STATE_NULL); + gst_object_unref(data.pipeline); + return 0; +} \ No newline at end of file diff --git a/build/Makefile b/build/Makefile index 58a4311..e2803b2 100644 --- a/build/Makefile +++ b/build/Makefile @@ -123,32 +123,32 @@ BasicTutorial/fast: $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/build .PHONY : BasicTutorial/fast -basic-tutorial-7.o: basic-tutorial-7.c.o +basic-tutorial-8.o: basic-tutorial-8.c.o -.PHONY : basic-tutorial-7.o +.PHONY : basic-tutorial-8.o # target to build an object file -basic-tutorial-7.c.o: - $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/basic-tutorial-7.c.o -.PHONY : basic-tutorial-7.c.o +basic-tutorial-8.c.o: + $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/basic-tutorial-8.c.o +.PHONY : basic-tutorial-8.c.o -basic-tutorial-7.i: basic-tutorial-7.c.i +basic-tutorial-8.i: basic-tutorial-8.c.i -.PHONY : basic-tutorial-7.i +.PHONY : basic-tutorial-8.i # target to preprocess a source file -basic-tutorial-7.c.i: - $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/basic-tutorial-7.c.i -.PHONY : basic-tutorial-7.c.i +basic-tutorial-8.c.i: + $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/basic-tutorial-8.c.i +.PHONY : basic-tutorial-8.c.i -basic-tutorial-7.s: basic-tutorial-7.c.s +basic-tutorial-8.s: basic-tutorial-8.c.s -.PHONY : basic-tutorial-7.s +.PHONY : basic-tutorial-8.s # target to generate assembly for a file -basic-tutorial-7.c.s: - $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/basic-tutorial-7.c.s -.PHONY : basic-tutorial-7.c.s +basic-tutorial-8.c.s: + $(MAKE) -f CMakeFiles/BasicTutorial.dir/build.make CMakeFiles/BasicTutorial.dir/basic-tutorial-8.c.s +.PHONY : basic-tutorial-8.c.s # Help Target help: @@ -159,9 +159,9 @@ help: @echo "... rebuild_cache" @echo "... edit_cache" @echo "... BasicTutorial" - @echo "... basic-tutorial-7.o" - @echo "... basic-tutorial-7.i" - @echo "... basic-tutorial-7.s" + @echo "... basic-tutorial-8.o" + @echo "... basic-tutorial-8.i" + @echo "... basic-tutorial-8.s" .PHONY : help