From 3ea91ad52e072fa97889396be26dcc6ff796300f Mon Sep 17 00:00:00 2001 From: Joungkook Seo Date: Mon, 10 Aug 2015 10:48:42 +0900 Subject: [PATCH] Update the code for sync with SPIN 2.4 (Muxer) Change-Id: I0c673e63606be12bef08c90345d9e8b65bd44cb7 Signed-off-by: Joungkook Seo --- doc/mediamuxer_doc.h | 2 + include/mediamuxer.h | 51 ++- include/mediamuxer_port.h | 52 ++- src/mediamuxer.c | 82 +++- src/mediamuxer_port.c | 38 +- src/port_gst/mediamuxer_port_gst.c | 71 ++- test/mediamuxer_test.c | 860 +++++++++++++++++++++---------------- 7 files changed, 750 insertions(+), 406 deletions(-) diff --git a/doc/mediamuxer_doc.h b/doc/mediamuxer_doc.h index d955b47..91e2e9e 100755 --- a/doc/mediamuxer_doc.h +++ b/doc/mediamuxer_doc.h @@ -43,6 +43,7 @@ * mediamuxer_set_data_sink() * mediamuxer_add_track(1) * mediamuxer_add_track(2) [add more tracks, if needed] + * mediamuxer_prepare() * mediamuxer_start() * while() * if (is_track(1)_data_available) @@ -54,6 +55,7 @@ * else * mediamuxer_close_track(2) * mediamuxer_stop() + * mediamuxer_unprepare() * mediamuxer_destroy() */ diff --git a/include/mediamuxer.h b/include/mediamuxer.h index 0a382b1..6b601b8 100755 --- a/include/mediamuxer.h +++ b/include/mediamuxer.h @@ -145,13 +145,13 @@ int mediamuxer_set_data_sink(mediamuxer_h muxer, char *path, mediamuxer_output_f * @pre The media muxer state must be set to #MEDIAMUXER_STATE_IDLE. * @see #media_format_h * @see mediamuxer_create() - * @see mediamuxer_start() + * @see mediamuxer_prepare() * */ int mediamuxer_add_track(mediamuxer_h muxer, media_format_h media_format, int *track_index); /** - * @brief Starts the media muxer. - * @remarks Initiates the necessary parameters, and keeps the muxer ready for writing data. + * @brief Prepares the media muxer. + * @remarks Initiates the necessary parameters. * @since_tizen 3.0 * @param[in] muxer The media muxer handle * @return @c 0 on success, otherwise a negative error value @@ -161,6 +161,22 @@ int mediamuxer_add_track(mediamuxer_h muxer, media_format_h media_format, int *t * @pre The media muxer state must be set to #MEDIAMUXER_STATE_IDLE. * @post The media muxer state will be #MEDIAMUXER_STATE_READY. * @see mediamuxer_create() + * @see mediamuxer_unprepare() + * */ +int mediamuxer_prepare(mediamuxer_h muxer); + +/** + * @brief Starts the media muxer. + * @remarks Keeps the muxer ready for writing data. + * @since_tizen 3.0 + * @param[in] muxer The media muxer handle + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIAMUXER_ERROR_NONE Successful + * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state + * @pre The media muxer state must be set to #MEDIAMUXER_STATE_READY. + * @post The media muxer state will be #MEDIAMUXER_STATE_MUXING. + * @see mediamuxer_prepare() * @see mediamuxer_stop() * */ int mediamuxer_start(mediamuxer_h muxer); @@ -175,10 +191,10 @@ int mediamuxer_start(mediamuxer_h muxer); * @retval #MEDIAMUXER_ERROR_NONE Successful * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state - * @pre The media muxer state must be set to #MEDIAMUXER_STATE_READY by calling mediamuxer_start() or + * @pre The media muxer state must be set to #MEDIAMUXER_STATE_READY by calling mediamuxer_prepare() or * set to #MEDIAMUXER_STATE_PAUSED by calling mediamuxer_pause(). * @post The media muxer state will be #MEDIAMUXER_STATE_MUXING. - * @see mediamuxer_start() + * @see mediamuxer_prepare() * @see mediamuxer_close_track() * @see mediamuxer_pause() * @see #media_packet_h @@ -197,7 +213,7 @@ int mediamuxer_write_sample(mediamuxer_h muxer, int track_index, media_packet_h * @pre The media muxer state must be set to #MEDIAMUXER_STATE_MUXING. * @see mediamuxer_write_sample() * @see mediamuxer_pause() - * @see mediamuxer_stop() + * @see mediamuxer_unprepare() * @see #mediamuxer_error_e * */ int mediamuxer_close_track(mediamuxer_h muxer, int track_index); @@ -237,21 +253,38 @@ int mediamuxer_resume(mediamuxer_h muxer); /** * @brief Stops the media muxer. - * @remarks Unrefs the variables created after calling mediamuxer_start(). + * @remarks Keeps the muxer ready for writing data. + * @since_tizen 3.0 + * @param[in] muxer The media muxer handle + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIAMUXER_ERROR_NONE Successful + * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state + * @pre The media muxer state must be set to #MEDIAMUXER_STATE_MUXING + * or #MEDIAMUXER_STATE_PAUSED. + * @post The media muxer state will be #MEDIAMUXER_STATE_READY. + * @see mediamuxer_start() + * @see mediamuxer_unprepare() + * */ +int mediamuxer_stop(mediamuxer_h muxer); + +/** + * @brief Unprepares the media muxer. + * @remarks Unrefs the variables created after calling mediamuxer_prepare(). * @since_tizen 3.0 * @param[in] muxer The media muxer handle * @return @c 0 on success, otherwise a negative error value * @retval #MEDIAMUXER_ERROR_NONE Successful * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state - * @pre The media muxer state must be set to #MEDIAMUXER_STATE_MUXING by calling mediamuxer_start() or + * @pre The media muxer state must be set to #MEDIAMUXER_STATE_READY or * set to #MEDIAMUXER_STATE_PAUSED by calling mediamuxer_pause(). * @post The media muxer state will be #MEDIAMUXER_STATE_IDLE. * @see mediamuxer_write_sample() * @see mediamuxer_pause() * @see mediamuxer_destroy() * */ -int mediamuxer_stop(mediamuxer_h muxer); +int mediamuxer_unprepare(mediamuxer_h muxer); /** * @brief Removes the instance of media muxer and clear all its context memory. diff --git a/include/mediamuxer_port.h b/include/mediamuxer_port.h index 191aaf7..93396fb 100755 --- a/include/mediamuxer_port.h +++ b/include/mediamuxer_port.h @@ -64,7 +64,7 @@ extern "C" { @par Most of functions which change muxer state work as synchronous. But, - mx_start() should be used asynchronously. Both mx_pause() and mx__resume() + mx_prepare() should be used asynchronously. Both mx_pause() and mx__resume() should also be used asynchronously in the case of streaming data. So, application have to confirm the result of those APIs through message callback function. @@ -332,11 +332,13 @@ typedef struct _media_port_muxer_ops { /* Add new ops at the end of structure, no order change */ int (*set_data_sink)(MMHandleType pHandle, char *uri, mediamuxer_output_format_e format); int (*add_track)(MMHandleType pHandle, media_format_h media_format, int *track_index); + int (*prepare)(MMHandleType pHandle); int (*start)(MMHandleType pHandle); int (*write_sample)(MMHandleType pHandle, int track_index, media_packet_h inbuf); int (*close_track)(MMHandleType pHandle, int track_index); int (*pause)(MMHandleType pHandle); int (*resume)(MMHandleType pHandle); + int (*unprepare)(MMHandleType pHandle); int (*stop)(MMHandleType pHandle); int (*destroy)(MMHandleType pHandle); int (*set_error_cb)(MMHandleType pHandle, mx_error_cb callback, void* user_data); @@ -422,6 +424,26 @@ int mx_destroy(MMHandleType muxer); * * @par Example * @code +if (mx_prepare(g_muxer) != MX_ERROR_NONE) +{ + MX_E("failed to prepare muxer\n"); +} + * @endcode + */ +int mx_prepare(MMHandleType muxer); + +/** + * This function starts the muxer object. \n + * For GST-port, this function sets the pipeline to playing + * + * @param muxer [in] Handle of muxer + * + * @return This function returns zero on success, or negative value with error + code. + * @see mx_stop + * + * @par Example + * @code if (mx_start(g_muxer) != MX_ERROR_NONE) { MX_E("failed to start muxer\n"); @@ -481,7 +503,7 @@ int mx_write_sample(MMHandleType mediamuxer, int track_index, media_packet_h inb * * @return This function returns zero on success, or negative value with error code. - * @see mx_stop + * @see mx_unprepare * * @par Example * @code @@ -494,14 +516,14 @@ if (mx_close_track(g_muxer,1) != MX_ERROR_NONE) int mx_close_track(MMHandleType mediamuxer, int track_index); /** - * This function stops/un-prepares the muxer object. \n - * For GST-port, this function unrefs necessary gst elemetns + * This function stops the muxer object. \n + * For GST-port, this function sets the pipeline to ready * * @param muxer [in] Handle of muxer * * @return This function returns zero on success, or negative value with error code. - * @see mx_stop + * @see mx_start * * @par Example * @code @@ -514,6 +536,26 @@ if (mx_stop(g_muxer) != MX_ERROR_NONE) int mx_stop(MMHandleType mediamuxer); /** + * This function stops/un-prepares the muxer object. \n + * For GST-port, this function unrefs necessary gst elemetns + * + * @param muxer [in] Handle of muxer + * + * @return This function returns zero on success, or negative value with error + code. + * @see mx_unprepare + * + * @par Example + * @code +if (mx_unprepare(g_muxer) != MX_ERROR_NONE) +{ + MX_E("failed to unprepare muxer\n"); +} + * @endcode + */ +int mx_unprepare(MMHandleType mediamuxer); + +/** * This function pauses the muxing operation. \n * For GST-port, this function pauses the pipeline * diff --git a/src/mediamuxer.c b/src/mediamuxer.c index aa75887..6618f5b 100644 --- a/src/mediamuxer.c +++ b/src/mediamuxer.c @@ -64,7 +64,8 @@ int mediamuxer_create(mediamuxer_h *muxer) /* set callback */ mx_set_error_cb(handle->mx_handle, (mediamuxer_error_cb)_mediamuxer_error_cb, handle); - handle->muxer_state = MEDIAMUXER_STATE_IDLE; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_IDLE; return MEDIAMUXER_ERROR_NONE; } } @@ -129,13 +130,39 @@ int mediamuxer_add_track(mediamuxer_h muxer, media_format_h media_format, int *t return ret; } +int mediamuxer_prepare(mediamuxer_h muxer) +{ + MX_I("mediamuxer_prepare\n"); + int ret = MEDIAMUXER_ERROR_NONE; + MUXER_INSTANCE_CHECK(muxer); + mediamuxer_s *handle = (mediamuxer_s *)(muxer); + if (handle->muxer_state == MEDIAMUXER_STATE_IDLE) { + ret = mx_prepare(handle->mx_handle); + if (ret != MEDIAMUXER_ERROR_NONE) { + MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)", + __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION); + ret = MEDIAMUXER_ERROR_INVALID_OPERATION; + } else { + MX_I("[CoreAPI][%s] prepare successful, handle : %p", + __FUNCTION__, handle); + } + } else { + MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)", + __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); + return MEDIAMUXER_ERROR_INVALID_STATE; + } + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_READY; + return ret; +} + int mediamuxer_start(mediamuxer_h muxer) { MX_I("mediamuxer_start\n"); int ret = MEDIAMUXER_ERROR_NONE; MUXER_INSTANCE_CHECK(muxer); mediamuxer_s *handle = (mediamuxer_s *)(muxer); - if (handle->muxer_state == MEDIAMUXER_STATE_IDLE) { + if (handle->muxer_state == MEDIAMUXER_STATE_READY) { ret = mx_start(handle->mx_handle); if (ret != MEDIAMUXER_ERROR_NONE) { MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)", @@ -150,7 +177,8 @@ int mediamuxer_start(mediamuxer_h muxer) __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); return MEDIAMUXER_ERROR_INVALID_STATE; } - handle->muxer_state = MEDIAMUXER_STATE_READY; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_MUXING; return ret; } @@ -180,7 +208,8 @@ int mediamuxer_write_sample(mediamuxer_h muxer, int track_index, media_packet_h __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); return MEDIAMUXER_ERROR_INVALID_STATE; } - handle->muxer_state = MEDIAMUXER_STATE_MUXING; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_MUXING; return ret; } @@ -237,7 +266,8 @@ int mediamuxer_pause(mediamuxer_h muxer) __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); return MEDIAMUXER_ERROR_INVALID_STATE; } - handle->muxer_state = MEDIAMUXER_STATE_PAUSED; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_PAUSED; return ret; } @@ -263,7 +293,8 @@ int mediamuxer_resume(mediamuxer_h muxer) __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); return MEDIAMUXER_ERROR_INVALID_STATE; } - handle->muxer_state = MEDIAMUXER_STATE_MUXING; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_MUXING; return ret; } @@ -273,17 +304,44 @@ int mediamuxer_stop(mediamuxer_h muxer) int ret = MEDIAMUXER_ERROR_NONE; MUXER_INSTANCE_CHECK(muxer); mediamuxer_s *handle = (mediamuxer_s *)(muxer); + if (handle->muxer_state == MEDIAMUXER_STATE_MUXING + || handle->muxer_state == MEDIAMUXER_STATE_PAUSED) { + ret = mx_stop(handle->mx_handle); + if (ret != MEDIAMUXER_ERROR_NONE) { + MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)", + __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION); + ret = MEDIAMUXER_ERROR_INVALID_OPERATION; + } else { + MX_I("[CoreAPI][%s] stop successful, handle : %p", + __FUNCTION__, handle); + } + } else { + MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)", + __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); + return MEDIAMUXER_ERROR_INVALID_STATE; + } + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_READY; + return ret; +} + +int mediamuxer_unprepare(mediamuxer_h muxer) +{ + MX_I("mediamuxer_unprepare\n"); + int ret = MEDIAMUXER_ERROR_NONE; + MUXER_INSTANCE_CHECK(muxer); + mediamuxer_s *handle = (mediamuxer_s *)(muxer); if (handle->muxer_state == MEDIAMUXER_STATE_READY || handle->muxer_state == MEDIAMUXER_STATE_MUXING || handle->muxer_state == MEDIAMUXER_STATE_PAUSED) { - ret = mx_stop(handle->mx_handle); + ret = mx_unprepare(handle->mx_handle); if (ret != MEDIAMUXER_ERROR_NONE) { MX_E ("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)", __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION); ret = MEDIAMUXER_ERROR_INVALID_OPERATION; } else { - MX_I("[CoreAPI][%s] stop successful, handle : %p", + MX_I("[CoreAPI][%s] unprepare successful, handle : %p", __FUNCTION__, handle); } } else { @@ -291,7 +349,8 @@ int mediamuxer_stop(mediamuxer_h muxer) __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); return MEDIAMUXER_ERROR_INVALID_STATE; } - handle->muxer_state = MEDIAMUXER_STATE_IDLE; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_IDLE; return ret; } @@ -317,7 +376,8 @@ int mediamuxer_destroy(mediamuxer_h muxer) __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE); return MEDIAMUXER_ERROR_INVALID_STATE; } - handle->muxer_state = MEDIAMUXER_STATE_NONE; + if (ret == MEDIAMUXER_ERROR_NONE) + handle->muxer_state = MEDIAMUXER_STATE_NONE; return ret; } @@ -345,9 +405,7 @@ int mediamuxer_set_error_cb(mediamuxer_h muxer, mediamuxer_error_cb callback, vo handle->error_cb = callback; handle->error_cb_userdata = user_data; - MX_I("set error_cb(%p)", callback); - return MEDIAMUXER_ERROR_NONE; } diff --git a/src/mediamuxer_port.c b/src/mediamuxer_port.c index 81bc5cc..1b46378 100644 --- a/src/mediamuxer_port.c +++ b/src/mediamuxer_port.c @@ -55,7 +55,7 @@ int mx_create(MMHandleType *muxer) MEDIAMUXER_CHECK_NULL(pOps); new_muxer->muxer_ops = pOps; - MX_I("mx_create allocating new_demuxer->demuxer_ops %p:\n", + MX_I("mx_create allocating new_muxer->muxer_ops %p:\n", new_muxer->muxer_ops); pOps->n_size = sizeof(media_port_muxer_ops); /* load ini files */ @@ -115,6 +115,24 @@ ERROR: return ret; } +int mx_prepare(MMHandleType mediamuxer) +{ + int ret = MX_ERROR_NONE; + mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer); + MEDIAMUXER_FENTER(); + MEDIAMUXER_CHECK_NULL(mx_handle); + media_port_muxer_ops *pOps = mx_handle->muxer_ops; + MEDIAMUXER_CHECK_NULL(pOps); + ret = pOps->prepare(mx_handle->mxport_handle); + MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR, + "error while preparing"); + MEDIAMUXER_FLEAVE(); + return ret; +ERROR: + MEDIAMUXER_FLEAVE(); + return ret; +} + int mx_start(MMHandleType mediamuxer) { int ret = MX_ERROR_NONE; @@ -215,6 +233,24 @@ int mx_stop(MMHandleType mediamuxer) MEDIAMUXER_CHECK_NULL(pOps); ret = pOps->stop(mx_handle->mxport_handle); MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR, + "error while stopping"); + MEDIAMUXER_FLEAVE(); + return ret; +ERROR: + MEDIAMUXER_FLEAVE(); + return ret; +} + +int mx_unprepare(MMHandleType mediamuxer) +{ + int ret = MX_ERROR_NONE; + mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer); + MEDIAMUXER_FENTER(); + MEDIAMUXER_CHECK_NULL(mx_handle); + media_port_muxer_ops *pOps = mx_handle->muxer_ops; + MEDIAMUXER_CHECK_NULL(pOps); + ret = pOps->unprepare(mx_handle->mxport_handle); + MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR, "error while destroying"); MEDIAMUXER_FLEAVE(); return ret; diff --git a/src/port_gst/mediamuxer_port_gst.c b/src/port_gst/mediamuxer_port_gst.c index 98b2344..7ef56ff 100644 --- a/src/port_gst/mediamuxer_port_gst.c +++ b/src/port_gst/mediamuxer_port_gst.c @@ -30,6 +30,7 @@ static int gst_muxer_set_data_sink(MMHandleType pHandle, char *uri, mediamuxer_output_format_e format); static int gst_muxer_add_track(MMHandleType pHandle, media_format_h media_format, int *track_index); +static int gst_muxer_prepare(MMHandleType pHandle); static int gst_muxer_start(MMHandleType pHandle); static int gst_muxer_write_sample(MMHandleType pHandle, int track_index, media_packet_h inbuf); @@ -37,6 +38,7 @@ static int gst_muxer_close_track(MMHandleType pHandle, int track_index); static int gst_muxer_pause(MMHandleType pHandle); static int gst_muxer_resume(MMHandleType pHandle); static int gst_muxer_stop(MMHandleType pHandle); +static int gst_muxer_unprepare(MMHandleType pHandle); static int gst_muxer_destroy(MMHandleType pHandle); static int gst_set_error_cb(MMHandleType pHandle, gst_error_cb callback, void* user_data); @@ -47,12 +49,14 @@ static media_port_muxer_ops def_mux_ops = { .init = gst_muxer_init, .set_data_sink = gst_muxer_set_data_sink, .add_track = gst_muxer_add_track, + .prepare = gst_muxer_prepare, .start = gst_muxer_start, .write_sample = gst_muxer_write_sample, .close_track = gst_muxer_close_track, .pause = gst_muxer_pause, .resume = gst_muxer_resume, .stop = gst_muxer_stop, + .unprepare = gst_muxer_unprepare, .destroy = gst_muxer_destroy, .set_error_cb = gst_set_error_cb, }; @@ -489,9 +493,9 @@ mx_ret_e _gst_create_pipeline(mxgst_handle_t *gst_handle) gst_handle->bus_watch_id = gst_bus_add_watch(bus, _mx_gst_bus_call, gst_handle); gst_object_unref(bus); - /* set pipeline state to PLAYING */ + /* set pipeline state to READY */ MEDIAMUXER_ELEMENT_SET_STATE(GST_ELEMENT_CAST(gst_handle->pipeline), - GST_STATE_PLAYING); + GST_STATE_READY); return MX_ERROR_NONE; STATE_CHANGE_FAILED: @@ -524,14 +528,14 @@ ERROR: return ret; } -static int gst_muxer_start(MMHandleType pHandle) +static int gst_muxer_prepare(MMHandleType pHandle) { MEDIAMUXER_FENTER(); int ret = MX_ERROR_NONE; MEDIAMUXER_CHECK_NULL(pHandle); mxgst_handle_t *new_mediamuxer = (mxgst_handle_t *) pHandle; - MX_I("__gst_muxer_start adding elements to the pipeline:%p\n", new_mediamuxer); + MX_I("__gst_muxer_prepare adding elements to the pipeline:%p\n", new_mediamuxer); ret = _gst_create_pipeline(new_mediamuxer); MEDIAMUXER_FLEAVE(); return ret; @@ -542,6 +546,34 @@ ERROR: return ret; } +static int gst_muxer_start(MMHandleType pHandle) +{ + MEDIAMUXER_FENTER(); + int ret = MX_ERROR_NONE; + MEDIAMUXER_CHECK_NULL(pHandle); + mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle; + + MX_I("__gst_muxer_start making pipeline to playing:%p\n", gst_handle); + + /* set pipeline state to PLAYING */ + MEDIAMUXER_ELEMENT_SET_STATE(GST_ELEMENT_CAST(gst_handle->pipeline), + GST_STATE_PLAYING); + + MEDIAMUXER_FLEAVE(); + return ret; + +STATE_CHANGE_FAILED: + MX_E("muxer state change failed, returning \n"); + ret = MX_ERROR_INVALID_ARGUMENT; + MEDIAMUXER_FLEAVE(); + return ret; +ERROR: + MX_E("muxer handle NULL, returning \n"); + ret = MX_ERROR_INVALID_ARGUMENT; + MEDIAMUXER_FLEAVE(); + return ret; +} + int __gst_codec_specific_caps(GstCaps *new_cap, media_format_mimetype_e mimetype) { @@ -1056,8 +1088,8 @@ ERROR: static int gst_muxer_resume(MMHandleType pHandle) { MEDIAMUXER_FENTER(); - MEDIAMUXER_CHECK_NULL(pHandle); int ret = MX_ERROR_NONE; + MEDIAMUXER_CHECK_NULL(pHandle); mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle; MX_I("gst_muxer_resume setting pipeline to playing"); @@ -1074,6 +1106,31 @@ ERROR: return ret; } +static int gst_muxer_stop(MMHandleType pHandle) +{ + MEDIAMUXER_FENTER(); + int ret = MX_ERROR_NONE; + MEDIAMUXER_CHECK_NULL(pHandle); + mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle; + + MX_I("gst_muxer_stop making pipeline to ready:%p\n", gst_handle); + /* set pipeline state to READY */ + MEDIAMUXER_ELEMENT_SET_STATE(GST_ELEMENT_CAST(gst_handle->pipeline), + GST_STATE_READY); + MEDIAMUXER_FLEAVE(); + return ret; +STATE_CHANGE_FAILED: + MX_E("muxer state change failed, returning \n"); + ret = MX_ERROR_INVALID_ARGUMENT; + MEDIAMUXER_FLEAVE(); + return ret; +ERROR: + MX_E("muxer handle NULL, returning \n"); + ret = MX_ERROR_INVALID_ARGUMENT; + MEDIAMUXER_FLEAVE(); + return ret; +} + mx_ret_e _gst_destroy_pipeline(mxgst_handle_t *gst_handle) { gint ret = MX_ERROR_NONE; @@ -1115,14 +1172,14 @@ mx_ret_e _gst_destroy_pipeline(mxgst_handle_t *gst_handle) return ret; } -static int gst_muxer_stop(MMHandleType pHandle) +static int gst_muxer_unprepare(MMHandleType pHandle) { MEDIAMUXER_FENTER(); int ret = MX_ERROR_NONE; MEDIAMUXER_CHECK_NULL(pHandle); mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle; - MX_I("__gst_muxer_stop setting eos to sources:%p\n", gst_handle); + MX_I("gst_muxer_unprepare setting eos to sources:%p\n", gst_handle); ret = _gst_destroy_pipeline(gst_handle); MEDIAMUXER_FLEAVE(); return ret; diff --git a/test/mediamuxer_test.c b/test/mediamuxer_test.c index 52efcfe..9ce398e 100644 --- a/test/mediamuxer_test.c +++ b/test/mediamuxer_test.c @@ -24,18 +24,14 @@ #include #include #include - +#include +#include #include #include #include "../include/mediamuxer_port.h" #include #include #include -/* Read encoded medial files locally: encoded A/V files along with info & caps */ -#define H264_FILE video_data -#define H264_INFO video_extra_info -#define AAC_FILE audio_data -#define AAC_INFO audio_extra_info /*----------------------------------------------------------------------- | GLOBAL VARIABLE DEFINITIONS: | @@ -49,22 +45,451 @@ media_format_h media_format_a = NULL; bool aud_eos = 0; bool vid_eos = 0; -char audio_extra_info[1000]; -char audio_data[1000]; -char video_extra_info[1000]; -char video_data[1000]; +char *aud_caps, *vid_caps; +char file_mp4[1000]; +bool have_mp4 = false; +int track_index_vid, track_index_aud; + +/* demuxer sturcture */ +typedef struct _CustomData +{ + GstElement *pipeline; + GstElement *source; + GstElement *demuxer; + GstElement *audioqueue; + GstElement *videoqueue; + + GstElement *audio_appsink; /* o/p of demuxer */ + GstElement *video_appsink; + GstElement *dummysink; + + char *saveLocation_audio; /* aac stream */ + char *saveLocation_video; /* h264 stream */ + GMainLoop *loop; + + GTimer *timer; +} CustomData; + + +/* demuxer helper functions */ +static void _video_app_sink_callback(GstElement *sink, CustomData *data); +static void _video_app_sink_eos_callback(GstElement *sink, CustomData *data); +static void _audio_app_sink_eos_callback(GstElement *sink, CustomData *data); +static void _on_pad_added(GstElement *element, GstPad *pad, CustomData *data); +static gboolean _bus_call(GstBus *bus, GstMessage *msg, gpointer data); + +/* Demuxer audio-appsink buffer receive callback*/ +static void _audio_app_sink_callback(GstElement *sink, CustomData *data) +{ + GstBuffer *buffer; + media_format_h audfmt; + media_packet_h aud_pkt; + track_index_aud = 2; /* track_index=2 for audio */ + guint8 *dptr; + static int count = 0; + if (count == 0) + g_print("\ngst-1.0 audio\n"); + GstSample *sample; + uint64_t ns; + int key; + GstMapInfo map; + g_signal_emit_by_name(sink, "pull-sample", &sample); + buffer = gst_sample_get_buffer(sample); + if (buffer) { + /* Print a * to indicate a received buffer */ + g_print("\na%d: ",++count); + + if (gst_buffer_map(buffer, &map, GST_MAP_READ)) { + if (!GST_BUFFER_FLAG_IS_SET(buffer,GST_BUFFER_FLAG_DELTA_UNIT)) { + /* g_print( " Key Frame \n"); */ + key = 1; + } else { + /* g_print( " NOT a Key Frame \n"); */ + key = 0; + } + + if (media_format_create(&audfmt)) { + g_print("media_format_create failed\n"); + return; + } + + if (media_format_set_audio_mime(audfmt, MEDIA_FORMAT_AAC)) { + g_print("media_format_set_audio_mime failed\n"); + return; + } + + if (media_packet_create(audfmt, NULL, NULL, &aud_pkt)) { + g_print("create audio media_packet failed\n"); + return; + } + + if (media_packet_alloc(aud_pkt)) { + g_print("audio media_packet alloc failed\n"); + return; + } + + media_packet_get_buffer_data_ptr(aud_pkt, (void **)&dptr); + memcpy((char*)dptr, map.data, map.size); + + if (media_packet_set_buffer_size(aud_pkt, (uint64_t)(map.size))) { + g_print("audio set_buffer_size failed\n"); + return; + } + + if (media_packet_get_buffer_size(aud_pkt, &ns)) { + g_print("unable to set the buffer size actual =%u, fixed %"PRIu64"\n",map.size,ns); + return; + } + + g_print(" fixed size %"PRIu64"\n", ns); + + if (media_packet_set_pts(aud_pkt, buffer->pts)) { + g_print("unable to set the pts\n"); + return; + } + + if (media_packet_set_dts(aud_pkt, buffer->dts)) { + g_print("unable to set the pts\n"); + return; + } + + if (media_packet_set_duration(aud_pkt, buffer->duration)) { + g_print("unable to set the pts\n"); + return; + } + + if (media_packet_set_flags(aud_pkt, key)) { + g_print("unable to set the flag size\n"); + return; + } + + if (media_packet_set_codec_data(aud_pkt, aud_caps, strlen(aud_caps)+1)) { + g_print("unable to set the audio codec data e\n"); + return; + } + + g_print("A write sample call. packet add:%p\n", aud_pkt); + mediamuxer_write_sample(myMuxer, track_index_aud, aud_pkt); + + media_packet_destroy(aud_pkt); + } + } +} + +/* Demuxer video-appsink buffer receive callback*/ +static void _video_app_sink_callback(GstElement *sink, CustomData *data) +{ + GstBuffer *buffer; + media_format_h vidfmt; + media_packet_h vid_pkt; + track_index_vid = 1; /* track_index=1 for video */ + uint64_t ns; + static int count = 0; + unsigned int vsize; + int key; + guint8 *dptr; + GstMapInfo map; + if (count == 0) + g_print("\ngst-1.0 Video\n"); + GstSample *sample; + g_signal_emit_by_name(sink, "pull-sample", &sample); + buffer = gst_sample_get_buffer(sample); + + if (buffer) { + /* Print a * to indicate a received buffer */ + g_print("v%d: ", ++count); + + g_print("PTS=%llu\n", buffer->pts); + + if (gst_buffer_map(buffer, &map, GST_MAP_READ)) { + if (media_format_create(&vidfmt)) { + g_print("media_format_create failed\n"); + return; + } + + if (media_format_set_video_mime(vidfmt, MEDIA_FORMAT_H264_SP)) { + g_print("media_format_set_vidio_mime failed\n"); + return; + } + + if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { + /* g_print("Key Frame\n"); */ + key = 1; + } else { + /* g_print("NOT a Key Frame\n"); */ + key = 0; + } + + vsize = map.size; + media_format_set_video_width(vidfmt, vsize/2+1); + media_format_set_video_height(vidfmt, vsize/2+1); + /*frame rate is came from the caps filter of demuxer*/ + if (media_format_set_video_frame_rate(vidfmt, 30)) { + g_print("media_format_set_video_frame_rate failed\n"); + return; + } + + if (media_packet_create(vidfmt, NULL, NULL, &vid_pkt)) { + g_print("create video media_packet failed\n"); + return; + } + + if (media_packet_alloc(vid_pkt)) { + g_print("video media_packet alloc failed\n"); + return; + } + + media_packet_get_buffer_data_ptr(vid_pkt, (void**)&dptr); + media_packet_get_buffer_size(vid_pkt, &ns); + g_print("set v buf size as %"PRIu64", data size=%d\n", ns, vsize); + memcpy((char*)dptr, map.data,map.size); + + if (media_packet_set_buffer_size(vid_pkt, (uint64_t)(map.size))) { + g_print("video set_buffer_size failed\n"); + return; + } + + if (media_packet_get_buffer_size(vid_pkt, &ns)) { + g_print("unable to set the buffer size actual =%d, fixed %"PRIu64"\n", map.size, ns); + return; + } + + g_print("fixed size %"PRIu64"\n",ns); + + if (media_packet_set_pts(vid_pkt, buffer->pts)) { + g_print("unable to set the pts\n"); + return; + } + + if (media_packet_set_dts(vid_pkt, buffer->dts)) { + g_print("unable to set the pts\n"); + return; + } + + if (media_packet_set_duration(vid_pkt, buffer->duration)) { + g_print("unable to set the pts\n"); + return; + } + + if (media_packet_set_flags(vid_pkt, key)) { + g_print("unable to set the flag size\n"); + return; + } + if (media_packet_set_codec_data(vid_pkt, vid_caps, strlen(vid_caps)+1)) { + g_print("unable to set the video codec data e\n"); + return; + } + + g_print("A write sample call. packet add:%p\n", vid_pkt); + mediamuxer_write_sample(myMuxer, track_index_vid, vid_pkt); + media_packet_destroy(vid_pkt); + } + } + +} + +/* demuxer video appsink eos callback */ +static void _video_app_sink_eos_callback(GstElement *sink, CustomData *data) +{ + mediamuxer_close_track(myMuxer, track_index_vid); + g_print("\n video h264 eos reached \n"); + vid_eos = 1; + if (aud_eos == 1) + g_main_loop_quit(data->loop); +} + +/* demuxer audio appsink eos callback */ +static void _audio_app_sink_eos_callback(GstElement *sink, CustomData *data) +{ + mediamuxer_close_track(myMuxer, track_index_aud); + g_print("\n audio AAC eos reached \n"); + aud_eos = 1; + if (vid_eos == 1) + g_main_loop_quit(data->loop); +} + +/* demuxer on_pad callback */ +static void _on_pad_added(GstElement *element, GstPad *pad, CustomData *data) +{ + GstPadLinkReturn ret; + GstPad *sink_pad_audioqueue = gst_element_get_static_pad(data->audioqueue, "sink"); + GstPad *sink_pad_videoqueue = gst_element_get_static_pad(data->videoqueue, "sink"); + GstCaps *new_pad_aud_caps = NULL; + GstCaps *new_pad_vid_caps = NULL; + GstCaps *new_pad_caps = NULL; + GstStructure *new_pad_struct = NULL; + const gchar *new_pad_type = NULL; + char *caps; + g_print("Received new pad '%s' from '%s':\n", GST_PAD_NAME(pad), GST_ELEMENT_NAME(element)); + + new_pad_caps = gst_pad_get_current_caps(pad); + new_pad_struct = gst_caps_get_structure(new_pad_caps, 0); + new_pad_type = gst_structure_get_name(new_pad_struct); + + if (g_str_has_prefix(new_pad_type, "audio/mpeg")) { + new_pad_aud_caps = gst_pad_get_current_caps(pad); + caps = gst_caps_to_string(new_pad_aud_caps); + g_print("Aud caps:%s\n", caps); + aud_caps = caps; + + /* Link demuxer to audioqueue */ + ret = gst_pad_link(pad, sink_pad_audioqueue); + if (GST_PAD_LINK_FAILED(ret)) + g_print(" Type is but link failed.\n %s", new_pad_type); + else + g_print(" Link succeeded (type '%s').\n", new_pad_type); + + gst_element_link(data->audioqueue, data->audio_appsink); + g_object_set(data->audio_appsink, "emit-signals", TRUE, NULL); + g_signal_connect(data->audio_appsink, "new-sample", G_CALLBACK(_audio_app_sink_callback), data); + g_signal_connect(data->audio_appsink, "eos", G_CALLBACK(_audio_app_sink_eos_callback), data); + + /* Link audioqueue->audio_appsink and save/Give to appsrc of muxer */ + gst_element_set_state(data->audio_appsink, GST_STATE_PLAYING); + /* one has to set the newly added element to the same state as the rest of the elements. */ + } else if (g_str_has_prefix(new_pad_type, "video/x-h264")) { + new_pad_vid_caps = gst_pad_get_current_caps(pad); + caps = gst_caps_to_string(new_pad_vid_caps); + g_print("Video:%s\n",caps); + vid_caps = caps; + + /* link demuxer with videoqueue */ + ret = gst_pad_link(pad, sink_pad_videoqueue); + if (GST_PAD_LINK_FAILED(ret)) + g_print("Type is '%s' but link failed.\n", new_pad_type); + else + g_print("Link succeeded (type '%s').\n", new_pad_type); + gst_element_link(data->videoqueue, data->video_appsink); + g_object_set(data->video_appsink, "emit-signals", TRUE, NULL); + g_signal_connect(data->video_appsink, "new-sample", G_CALLBACK(_video_app_sink_callback), data); + g_signal_connect(data->video_appsink, "eos", G_CALLBACK(_video_app_sink_eos_callback), data); + gst_element_set_state(data->video_appsink, GST_STATE_PLAYING); + /* one has to set the newly added element to the same state as the rest of the elements. */ + } else { + g_print(" It has type '%s' which is not raw A/V. Ignoring.\n", new_pad_type); + goto exit; + } + +exit: + if (new_pad_caps != NULL) + gst_caps_unref(new_pad_caps); + + gst_object_unref(sink_pad_audioqueue); + gst_object_unref(sink_pad_videoqueue); +} + +/* Demuxer bus_call */ +static gboolean _bus_call(GstBus *bus, GstMessage *mesg, gpointer data) +{ + GMainLoop *dmxr_loop = (GMainLoop*)data; + + switch (GST_MESSAGE_TYPE(mesg)) + { + case GST_MESSAGE_EOS: + g_print("End of stream\n"); + g_main_loop_quit(dmxr_loop); + break; + + case GST_MESSAGE_ERROR: + { + gchar *dbg; + GError *err; + gst_message_parse_error(mesg, &err, &dbg); + g_free(dbg); + g_printerr("Demuxer-Error:%s \n", err->message); + g_error_free(err); + g_main_loop_quit(dmxr_loop); + break; + } + default: + break; + } + return TRUE; +} + +/* Demux an mp4 file and generate encoded streams and extra data */ +int demux_mp4() +{ + CustomData data; + GMainLoop *loop_dmx; + GstBus *bus; + guint watch_id_for_bus; + + if (access(file_mp4, F_OK) == -1) { + /* mp4 file doesn't exist */ + g_print("mp4 Invalid file path."); + return -1; + } + + gst_init(NULL,NULL); + loop_dmx = g_main_loop_new(NULL, FALSE); + data.loop = loop_dmx; + + /* Create gstreamer elements for demuxer*/ + data.pipeline = gst_pipeline_new("DemuxerPipeline"); + data.source = gst_element_factory_make("filesrc", "file-source"); + data.demuxer = gst_element_factory_make("qtdemux", "mp4-demuxer"); + data.audioqueue = gst_element_factory_make("queue", "audio-queue"); + data.videoqueue = gst_element_factory_make("queue", "video-queue"); + + data.dummysink = gst_element_factory_make("fakesink", "fakesink"); + data.video_appsink = gst_element_factory_make("appsink", "video (h264) appsink"); + data.audio_appsink = gst_element_factory_make("appsink", "audio (AAC) appsink"); + + if (!data.pipeline || !data.source || !data.demuxer || !data.audioqueue + || !data.dummysink || !data.videoqueue || !data.audio_appsink || !data.video_appsink) { + g_print("Test-Suite: One gst-element can't be created. Exiting\n"); + return -1; + } + + /* Add msg-handler */ + bus = gst_pipeline_get_bus(GST_PIPELINE(data.pipeline)); + watch_id_for_bus = gst_bus_add_watch(bus, _bus_call, loop_dmx); + gst_object_unref(bus); + + /* Add gstreamer-elements into gst-pipeline */ + gst_bin_add_many(GST_BIN(data.pipeline), data.source, data.demuxer, data.dummysink, \ + data.audioqueue, data.videoqueue,data.audio_appsink, data.video_appsink, NULL); + + /* we set the input filename to the source element */ + g_object_set(G_OBJECT(data.source), "location", file_mp4, NULL); + + /* we link the elements together */ + gst_element_link(data.source, data.demuxer); + + /* Register demuxer callback */ + g_signal_connect(data.demuxer, "pad-added", G_CALLBACK(_on_pad_added), &data); + + /* play the pipeline */ + g_print("Now playing: %s\n", file_mp4); + gst_element_set_state(data.pipeline, GST_STATE_PLAYING); + + /* Run the loop till quit */ + g_print("gst-pipeline-Running...\n"); + g_main_loop_run(loop_dmx); + + /* Done with gst-loop. Free resources */ + gst_element_set_state(data.pipeline, GST_STATE_NULL); + + g_print("Unreferencing the gst-pipeline\n"); + gst_object_unref(GST_OBJECT(data.pipeline)); + g_source_remove(watch_id_for_bus); + g_main_loop_unref(loop_dmx); + return 0; +} + int test_mediamuxer_create() { g_print("test_mediamuxer_create\n"); g_print("%p", myMuxer); - if (mediamuxer_create(&myMuxer) - != MEDIAMUXER_ERROR_NONE) { + if (mediamuxer_create(&myMuxer) != MEDIAMUXER_ERROR_NONE) { g_print("mediamuxer create is failed\n"); } + g_print("\n Muxer->mx_handle created successfully with address=%p", - (void *)((mediamuxer_s *) myMuxer)->mx_handle); + (void *)((mediamuxer_s *)myMuxer)->mx_handle); g_print("\n Muxer handle created successfully with address=%p", myMuxer); @@ -90,6 +515,13 @@ int test_mediamuxer_destroy() return ret; } +int test_mediamuxer_prepare() +{ + g_print("mediamuxer_prepare completed \n"); + mediamuxer_prepare(myMuxer); + return 0; +} + int test_mediamuxer_start() { g_print("mediamuxer_start completed \n"); @@ -114,18 +546,18 @@ int test_mediamuxer_add_track_video() media_format_set_video_width(media_format, 640); media_format_set_video_height(media_format, 480); - media_format_set_video_avg_bps(media_format, 10); - media_format_set_video_max_bps(media_format, 10); + media_format_set_video_avg_bps(media_format, 256000); + media_format_set_video_max_bps(media_format, 256000); media_format_get_video_info(media_format, &mimetype, &width, &height, &avg_bps, &max_bps); - g_print("\n Video Mime trying to set: %x %x\n", (int)(mimetype), (int)(MEDIA_FORMAT_H264_SP)); + g_print("\n Video Mime trying to set: %x %x\n",(int)(mimetype),(int)(MEDIA_FORMAT_H264_SP)); g_print("\n Video param trying to set: (width, height, avg_bps, max_bps): %d %d %d %d \n", width, height, avg_bps, max_bps); /* To add video track */ mediamuxer_add_track(myMuxer, media_format, &track_index_vid); - g_print("audio track index returned is: %d", track_index_vid); + g_print("video track index returned is: %d", track_index_vid); return 0; } @@ -147,9 +579,9 @@ int test_mediamuxer_add_track_audio() if (media_format_set_audio_channel(media_format_a, 2) == MEDIA_FORMAT_ERROR_INVALID_OPERATION) g_print("Problem during media_format_set_audio_channel operation"); - media_format_set_audio_samplerate(media_format_a, 44000); - media_format_set_audio_bit(media_format_a, 1); - media_format_set_audio_avg_bps(media_format_a, 10); + media_format_set_audio_samplerate(media_format_a, 44100); + media_format_set_audio_bit(media_format_a, 32); + media_format_set_audio_avg_bps(media_format_a, 128000); media_format_set_audio_aac_type(media_format_a, true); media_format_get_audio_info(media_format_a, &mimetype, &channel, &samplerate, &bit, &avg_bps); @@ -177,313 +609,10 @@ int test_mediamuxer_set_error_cb() return ret; } -void *_write_video_data() -{ - FILE *pvFile; - FILE *pvFileInfo; - unsigned int size; - unsigned int vsize; - unsigned int is_video_readable = 1; - unsigned int is_video_pts_readable; - unsigned int is_video_dts_readable; - unsigned int is_video_duration_readable; - unsigned int is_video_flag_readable; - unsigned int is_video_key_readable; - unsigned long long int pts_vid; - unsigned long long int dts_vid; - unsigned long long int duration_vid; - int flg_vid; - int *status = (int *)g_malloc(sizeof(int) * 1); - *status = -1; - int track_index_vid = 1; /* track_index=2 for video */ - int vcount = 0; - guint8 *ptr_vid; - int key_vid; - char *vid_caps; - int ret_scan; - media_packet_h vid_pkt; - media_format_h vidfmt; - unsigned int vcap_size; - - pvFile = fopen(H264_FILE, "rb"); - pvFileInfo = fopen(H264_INFO, "rt"); - - if (pvFile == NULL || pvFileInfo == NULL) { - g_print("\nOne of the files (info/data) cant be loaded...\n"); - return (void *)status; - } - - ret_scan = fscanf(pvFileInfo, "%d\n", &size); - vid_caps = (char *)malloc(size + 1); - ret_scan = fscanf(pvFileInfo, "%[^\n]s\n", vid_caps); - g_print("\nV_Caps = %s\n", vid_caps); - vcap_size = size + 1; - - if (!ret_scan) { /* ToDo: repeat the same for every scanf */ - g_print("\nscan failed"); - return (void *)status; - } - - while (is_video_readable == 1) { - /* Read encoded video data */ - is_video_readable = fscanf(pvFileInfo, "%d\n", &vsize); - is_video_pts_readable = fscanf(pvFileInfo, "%llu\n", &pts_vid); - is_video_dts_readable = fscanf(pvFileInfo, "%llu\n", &dts_vid); - is_video_duration_readable = fscanf(pvFileInfo, "%llu\n", &duration_vid); - is_video_flag_readable = fscanf(pvFileInfo, "%u\n", &flg_vid); - is_video_key_readable = fscanf(pvFileInfo, "%d\n", &key_vid); - - if (is_video_readable == 1 && is_video_pts_readable == 1 && is_video_dts_readable == 1 - && is_video_duration_readable == 1 && is_video_flag_readable == 1 - && is_video_key_readable == 1) { - g_print("\nv%d: ", ++vcount); - g_print("\nv_Size: %d, v_pts: %llu, v_dts: %llu v_duration: %llu, v_flag: %d", - vsize, pts_vid, dts_vid, duration_vid, key_vid); - ptr_vid = g_malloc(vsize); - g_assert(ptr_vid); - vsize = fread(ptr_vid, 1, vsize, pvFile); - - if (media_format_create(&vidfmt)) { - g_print("media_format_create failed\n"); - return (void *)status; - } - if (media_format_set_video_mime(vidfmt, MEDIA_FORMAT_H264_SP)) { - g_print("media_format_set_audio_mime failed\n"); - return (void *)status; - } - media_format_set_video_width(vidfmt, vsize / 2 + 1); - media_format_set_video_height(vidfmt, vsize / 2 + 1); - /*frame rate is came from the caps filter of demuxer*/ - if (media_format_set_video_frame_rate(vidfmt, 30)) { - g_print("media_format_set_video_frame_rate failed\n"); - return (void *)status; - } - - uint64_t ns; - guint8 *dptr; - - if (media_packet_create(vidfmt, NULL, NULL, &vid_pkt)) { - g_print("\ncreate v media packet failed tc\n"); - return (void *)status; - } - - if (media_packet_alloc(vid_pkt)) { - g_print(" v media packet alloc failed\n"); - return (void *)status; - } - media_packet_get_buffer_data_ptr(vid_pkt, (void **)&dptr); - media_packet_get_buffer_size(vid_pkt, &ns); - g_print("set v buf size as %d, data size=%d\n", (int)ns, vsize); - - memcpy((char *)dptr, ptr_vid, vsize); - if (media_packet_set_buffer_size(vid_pkt, vsize)) { - g_print("set v buf size failed\n"); - return (void *)status; - } - - - if (media_packet_get_buffer_size(vid_pkt, &ns)) { - g_print("unable to set the v buffer size actual =%d, fixed %d\n", size, (int)ns); - return (void *)status; - } - g_print(" fixed size %d\n", (int)ns); - - if (media_packet_set_pts(vid_pkt, pts_vid)) { - g_print("unable to set the pts\n"); - return (void *)status; - } - if (media_packet_set_dts(vid_pkt, dts_vid)) { - g_print("unable to set the pts\n"); - return (void *)status; - } - if (media_packet_set_duration(vid_pkt, duration_vid)) { - g_print("unable to set the pts\n"); - return (void *)status; - } - - if (media_packet_set_flags(vid_pkt, flg_vid)) { - g_print("unable to set the flag size\n"); - return (void *)status; - } - if (media_packet_set_codec_data(vid_pkt, vid_caps, vcap_size)) { - g_print("unable to set the flag size\n"); - return (void *)status; - } - - mediamuxer_write_sample(myMuxer, track_index_vid, vid_pkt); - - media_packet_destroy(vid_pkt); - } else { - g_print("\nVideo while done in the test suite"); - mediamuxer_close_track(myMuxer, track_index_vid); - } - } - g_print("\n\n\n ******* Out of while loop ****** \n\n\n"); - fclose(pvFile); - fclose(pvFileInfo); - *status = 0; - return (void *)status; -} - -void *_write_audio_data() -{ - FILE *paFile; - FILE *paFileInfo; - unsigned int size; - unsigned int is_audio_readable = 1; - unsigned int is_audio_pts_readable; - unsigned int is_audio_dts_readable; - unsigned int is_audio_duration_readable; - unsigned int is_audio_flag_readable; - unsigned int is_audio_key_readable; - unsigned char *ptr1; - unsigned long long int pts; - unsigned long long int dts; - unsigned long long int duration; - int flg; - - int key; - int acount = 0; - int track_index_aud = 2; /* track_index=2 for audio */ - char *aud_caps; - int ret_scan; - media_packet_h aud_pkt; - media_format_h audfmt; - unsigned int acap_size; - int *status = (int *)g_malloc(sizeof(int) * 1); - *status = -1; - - paFileInfo = fopen(AAC_INFO, "rt"); - paFile = fopen(AAC_FILE, "rb"); - - if (paFile == NULL || paFileInfo == NULL) { - g_print("\nOne of the files (info/data) cant be loaded...\n"); - return (void *)status; - } - - ret_scan = fscanf(paFileInfo, "%d\n", &size); - aud_caps = (char *)malloc(1 + size); - ret_scan = fscanf(paFileInfo, "%[^\n]s\n", aud_caps); - g_print("\nA_Caps = %s\n", aud_caps); - acap_size = size + 1; - - if (!ret_scan) { /* ToDo: repeat the same for every scanf */ - g_print("\nscan failed"); - return (void *)status; - } - - while (is_audio_readable == 1) { - - /* Read encoded audio data */ - is_audio_readable = fscanf(paFileInfo, "%d\n", &size); - is_audio_pts_readable = fscanf(paFileInfo, "%llu\n", &pts); - is_audio_dts_readable = fscanf(paFileInfo, "%llu\n", &dts); - is_audio_duration_readable = fscanf(paFileInfo, "%llu\n", &duration); - is_audio_flag_readable = fscanf(paFileInfo, "%u\n", &flg); - is_audio_key_readable = fscanf(paFileInfo, "%d\n", &key); - - if (is_audio_readable == 1 && is_audio_pts_readable == 1 - && is_audio_dts_readable == 1 && is_audio_duration_readable == 1 - && is_audio_flag_readable == 1 && is_audio_key_readable == 1) { - g_print("\na%d: ", ++acount); - g_print("\nSize: %d, a_pts: %llu, a_dts: %llu, a_duration: %llu, a_flag:%d, a_key:%d", - size, pts, dts, duration, flg, key); - - if (media_format_create(&audfmt)) { - g_print("media_format_create failed\n"); - return (void *)status; - } - if (media_format_set_audio_mime(audfmt, MEDIA_FORMAT_AAC)) { - g_print("media_format_set_audio_mime failed\n"); - return (void *)status; - } - - ptr1 = g_malloc(size); - g_assert(ptr1); - - size = fread(ptr1, 1, size, paFile); - - /* To create media_pkt */ - uint64_t ns; - guint8 *dptr; - - if (media_packet_create(audfmt, NULL, NULL, &aud_pkt)) { - g_print("create audio media_packet failed\n"); - return (void *)status; - } - - if (media_packet_alloc(aud_pkt)) { - g_print("audio media_packet alloc failed\n"); - return (void *)status; - } - media_packet_get_buffer_data_ptr(aud_pkt, (void **)&dptr); - memcpy((char *)dptr, ptr1, size); - - if (media_packet_set_buffer_size(aud_pkt, (uint64_t)size)) { - g_print("audio set_buffer_size failed\n"); - return (void *)status; - } - - if (media_packet_get_buffer_size(aud_pkt, &ns)) { - g_print("unable to set the buffer size actual =%d, fixed %d\n", size, (int)ns); - return (void *)status; - } - - g_print(" fixed size %d\n", (int)ns); - - if (media_packet_set_pts(aud_pkt, pts)) { - g_print("unable to set the pts\n"); - return (void *)status; - } - - if (media_packet_set_dts(aud_pkt, dts)) { - g_print("unable to set the pts\n"); - return (void *)status; - } - - if (media_packet_set_duration(aud_pkt, duration)) { - g_print("unable to set the pts\n"); - return (void *)status; - } - - if (media_packet_set_flags(aud_pkt, key)) { - g_print("unable to set the flag size\n"); - return (void *)status; - } - if (media_packet_set_codec_data(aud_pkt, aud_caps, acap_size)) { - g_print("unable to set the audio codec data e\n"); - return (void *)status; - } - - mediamuxer_write_sample(myMuxer, track_index_aud, aud_pkt); - - media_packet_destroy(aud_pkt); - } else { - g_print("\nAudio while done in the test suite"); - mediamuxer_close_track(myMuxer, track_index_aud); - } - - } - g_print("\n\n\n ******* Out of while loop ****** \n\n\n"); - - fclose(paFile); - fclose(paFileInfo); - *status = 0; - return (void *)status; -} - int test_mediamuxer_write_sample() { - pthread_t thread[2]; - pthread_attr_t attr; - /* Initialize and set thread detached attribute */ - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - g_print("In main: creating thread for audio\n"); - pthread_create(&thread[0], &attr, _write_video_data, NULL); - pthread_create(&thread[1], &attr, _write_audio_data, NULL); - pthread_attr_destroy(&attr); + demux_mp4(); return 0; } @@ -491,6 +620,14 @@ int test_mediamuxer_stop() { g_print("test_mediamuxer_stop\n"); mediamuxer_stop(myMuxer); + return 0; +} + + +int test_mediamuxer_unprepare() +{ + g_print("test_mediamuxer_unprepare\n"); + mediamuxer_unprepare(myMuxer); media_format_unref(media_format_a); media_format_unref(media_format); return 0; @@ -529,10 +666,7 @@ void quit_testApp(void) enum { CURRENT_STATUS_MAINMENU, - CURRENT_STATUS_AUDIO_FILENAME, - CURRENT_STATUS_AUDIO_INFONAME, - CURRENT_STATUS_VIDEO_FILENAME, - CURRENT_STATUS_VIDEO_INFONAME, + CURRENT_STATUS_MP4_FILENAME }; int g_menu_state = CURRENT_STATUS_MAINMENU; @@ -560,16 +694,28 @@ void _interpret_main_menu(char *cmd) test_mediamuxer_set_data_sink(); } else if (strncmp(cmd, "d", 1) == 0) { test_mediamuxer_destroy(); + } else if (strncmp(cmd, "e", 1) == 0) { + test_mediamuxer_prepare(); } else if (strncmp(cmd, "s", 1) == 0) { test_mediamuxer_start(); } else if (strncmp(cmd, "a", 1) == 0) { - g_menu_state = CURRENT_STATUS_AUDIO_FILENAME; + if (have_mp4 == false) { + g_menu_state = CURRENT_STATUS_MP4_FILENAME; + have_mp4 = true; + } + test_mediamuxer_add_track_audio(); } else if (strncmp(cmd, "v", 1) == 0) { - g_menu_state = CURRENT_STATUS_VIDEO_FILENAME; + if (have_mp4 == false) { + g_menu_state = CURRENT_STATUS_MP4_FILENAME; + have_mp4 = true; + } + test_mediamuxer_add_track_video(); } else if (strncmp(cmd, "m", 1) == 0) { test_mediamuxer_write_sample(); - } else if (strncmp(cmd, "e", 1) == 0) { + } else if (strncmp(cmd, "t", 1) == 0) { test_mediamuxer_stop(); + } else if (strncmp(cmd, "u", 1) == 0) { + test_mediamuxer_unprepare(); } else if (strncmp(cmd, "p", 1) == 0) { test_mediamuxer_pause(); } else if (strncmp(cmd, "r", 1) == 0) { @@ -592,20 +738,9 @@ static void displaymenu(void) { if (g_menu_state == CURRENT_STATUS_MAINMENU) { display_sub_basic(); - } else if (g_menu_state == CURRENT_STATUS_AUDIO_FILENAME) { - g_print("*** input encoded audio_data path:\n"); - g_print("[This is the raw encoded audio file to be muxed]:"); - } else if (g_menu_state == CURRENT_STATUS_AUDIO_INFONAME) { - g_print("*** input encoded audio info (extra data) path\n"); - g_print("[This is the extra-information needed to mux."); - g_print("This includes gst-caps too]:"); - } else if (g_menu_state == CURRENT_STATUS_VIDEO_FILENAME) { - g_print("*** input encoded video path\n"); - g_print("[This is the raw encoded video file to be muxed]:"); - } else if (g_menu_state == CURRENT_STATUS_VIDEO_INFONAME) { - g_print("*** input encoded video info (extra data) path\n"); - g_print("[This is the extra-information needed to mux."); - g_print("This includes gst-caps too]:"); + } else if (g_menu_state == CURRENT_STATUS_MP4_FILENAME) { + g_print("*** input mp4 file path:\n"); + g_print("[This is the file from where demuxed data is fed to muxer]:"); } else { g_print("*** unknown status.\n"); exit(0); @@ -627,30 +762,9 @@ static void interpret(char *cmd) _interpret_main_menu(cmd); break; } - case CURRENT_STATUS_AUDIO_FILENAME: { - input_filepath(cmd); - strcpy(audio_data, cmd); - g_menu_state = CURRENT_STATUS_AUDIO_INFONAME; - break; - } - case CURRENT_STATUS_AUDIO_INFONAME: { - input_filepath(cmd); - strcpy(audio_extra_info, cmd); - test_mediamuxer_add_track_audio(); - g_menu_state = CURRENT_STATUS_MAINMENU; - - break; - } - case CURRENT_STATUS_VIDEO_FILENAME: { - input_filepath(cmd); - strcpy(video_data, cmd); - g_menu_state = CURRENT_STATUS_VIDEO_INFONAME; - break; - } - case CURRENT_STATUS_VIDEO_INFONAME: { + case CURRENT_STATUS_MP4_FILENAME: { input_filepath(cmd); - strcpy(video_extra_info, cmd); - test_mediamuxer_add_track_video(); + strcpy(file_mp4, cmd); g_menu_state = CURRENT_STATUS_MAINMENU; break; } @@ -670,12 +784,14 @@ static void display_sub_basic() g_print("o. Set Data Sink \t"); g_print("a. AddAudioTrack \t"); g_print("v. AddVideoTrack \t"); - g_print("s. Start \t"); - g_print("m. StartMuxing \t"); + g_print("e. prepare \t"); + g_print("s. start \t"); + g_print("m. startMuxing \t"); g_print("p. PauseMuxing \t"); g_print("r. ResumeMuxing \t"); g_print("b. set error callback \t"); - g_print("e. Stop (eos) \n"); + g_print("t. stop \t"); + g_print("u. UnPrepare \t"); g_print("d. destroy \t"); g_print("q. quit \t"); g_print("\n"); @@ -718,7 +834,7 @@ int main(int argc, char *argv[]) GMainLoop *loop = g_main_loop_new(NULL, 0); stdin_channel = g_io_channel_unix_new(0); g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL); - g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc) input, NULL); + g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc)input, NULL); displaymenu(); /* g_print("RUN main loop\n"); */ -- 2.7.4