/** catch probes from probe_uref */ static int uref_catch(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { if (event != UPROBE_PROBE_UREF) return uprobe_throw_next(uprobe, upipe, event, args); va_list args_copy; va_copy(args_copy, args); unsigned int signature = va_arg(args_copy, unsigned int); va_end(args_copy); if (signature != UPIPE_PROBE_UREF_SIGNATURE) return uprobe_throw_next(uprobe, upipe, event, args); if (upipe_source != NULL) { /* dump the pipeline before leaving */ if (dump != NULL) upipe_dump_open(NULL, NULL, dump, NULL, upipe_source, NULL); /* release the source to exit */ upipe_release(upipe_source); upipe_source = NULL; /* send demux output to /dev/null */ upipe_set_output(upipe_split_output, upipe_null); upipe_release(upipe_split_output); upipe_split_output = NULL; } else { /* second (or after) frame, do not output them */ upipe_set_output(upipe, upipe_null); } return UBASE_ERR_NONE; }
/** @internal @This catches events of the dec queue source. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_dec_qsrc(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_SOURCE_END: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_dec_qsrc_s); upipe_flush(glxplayer->upipe_glx_qsink); upipe_release(glxplayer->upipe_glx_qsink); return UBASE_ERR_NONE; } case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_dec_qsrc_s); struct upipe *avcdec = upipe_void_alloc_output(upipe, glxplayer->upipe_avcdec_mgr, uprobe_pfx_alloc_va( uprobe_use(&glxplayer->uprobe_avcdec_s), glxplayer->loglevel, "avcdec")); if (unlikely(avcdec == NULL)) return UBASE_ERR_ALLOC; upipe_set_option(avcdec, "threads", "2"); upipe_release(avcdec); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** @internal @This catches events of the qsrc of the glx (main) thread. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_glx_qsrc(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_SOURCE_END: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_glx_qsrc_s); upipe_release(upipe); pthread_join(glxplayer->src_thread_id, NULL); if (glxplayer->trickp) upipe_release(glxplayer->upipe_trickp); free(glxplayer->uri); return UBASE_ERR_NONE; } case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_glx_qsrc_s); struct upipe *trickp_pic; if (glxplayer->trickp) { glxplayer->upipe_trickp = upipe_void_alloc(glxplayer->upipe_trickp_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "trickp")); if (unlikely(glxplayer->upipe_trickp == NULL)) return UBASE_ERR_ALLOC; upipe_attach_uclock(glxplayer->upipe_trickp); trickp_pic = upipe_void_alloc_output_sub(upipe, glxplayer->upipe_trickp, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "trickp pic")); if (unlikely(trickp_pic == NULL)) return UBASE_ERR_ALLOC; } else trickp_pic = upipe; /* glx sink */ struct upipe *glx_sink = upipe_void_alloc_output(trickp_pic, glxplayer->upipe_glx_mgr, uprobe_gl_sink_cube_alloc( uprobe_pfx_alloc( uprobe_use(&glxplayer->uprobe_glx_s), glxplayer->loglevel, "glx"))); if (glxplayer->trickp) upipe_release(trickp_pic); if (unlikely(glx_sink == NULL)) return UBASE_ERR_ALLOC; upipe_glx_sink_init(glx_sink, 0, 0, 800, 480); upipe_attach_uclock(glx_sink); upipe_release(glx_sink); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** @internal @This catches events of the avcdec. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_avcdec(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_avcdec_s); struct uref *flow_def = va_arg(args, struct uref *); struct upipe *deint = upipe_void_alloc_output(upipe, glxplayer->upipe_filter_blend_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "deint")); if (unlikely(deint == NULL)) return UBASE_ERR_ALLOC; struct uref *output_flow = uref_dup(flow_def); if (unlikely(output_flow == NULL)) return UBASE_ERR_ALLOC; uref_pic_flow_clear_format(output_flow); if (unlikely(!ubase_check(uref_pic_flow_set_macropixel(output_flow, 1)) || !ubase_check(uref_pic_flow_set_planes(output_flow, 0)) || !ubase_check(uref_pic_flow_add_plane(output_flow, 1, 1, 3, "r8g8b8")))) { uref_free(output_flow); return UBASE_ERR_ALLOC; } struct upipe *yuvrgb = upipe_flow_alloc_output(deint, glxplayer->upipe_sws_mgr, uprobe_pfx_alloc_va(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "rgb"), output_flow); assert(yuvrgb != NULL); uref_free(output_flow); upipe_release(deint); glxplayer->upipe_glx_qsink = upipe_qsink_alloc(glxplayer->upipe_qsink_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "glx qsink"), glxplayer->upipe_glx_qsrc); if (unlikely(glxplayer->upipe_glx_qsink == NULL)) return UBASE_ERR_ALLOC; upipe_set_output(yuvrgb, glxplayer->upipe_glx_qsink); upipe_release(yuvrgb); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** @internal @This allocates a hls pipe. * * @param mgr management structure for this pipe type * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to allocated pipe, or NULL in case of failure */ static struct upipe *upipe_hls_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct upipe *upipe = upipe_hls_alloc_void(mgr, uprobe, signature, args); if (unlikely(upipe == NULL)) return NULL; struct upipe_hls *upipe_hls = upipe_hls_from_upipe(upipe); upipe_hls_init_urefcount(upipe); upipe_hls_init_urefcount_real(upipe); upipe_hls_init_probe_reader(upipe); upipe_hls_init_probe_master(upipe); upipe_hls_init_probe_null(upipe); upipe_hls_init_first_inner(upipe); upipe_hls_init_last_inner(upipe); upipe_hls_init_bin_input(upipe); upipe_hls_init_bin_output(upipe); upipe_hls->flow_def = NULL; upipe_hls->item = NULL; upipe_hls->sub_pipe_mgr = NULL; upipe_throw_ready(upipe); struct upipe *inner = NULL; struct upipe_mgr *upipe_m3u_reader_mgr = upipe_m3u_reader_mgr_alloc(); if (unlikely(!upipe_m3u_reader_mgr)) { upipe_err(upipe, "fail to allocate m3u reader manager"); upipe_release(upipe); return NULL; } inner = upipe_void_alloc( upipe_m3u_reader_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_reader), UPROBE_LOG_VERBOSE, "reader")); upipe_mgr_release(upipe_m3u_reader_mgr); if (unlikely(!inner)) { upipe_err(upipe, "fail to allocate m3u reader"); upipe_release(upipe); return NULL; } upipe_hls_store_bin_input(upipe, inner); return upipe; }
/** @internal @This allocates a video blank pipe. * * @param mgr pointer to upipe manager * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return an allocated pipe */ static struct upipe *upipe_vblk_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct uref *flow_def; struct upipe *upipe = upipe_vblk_alloc_flow(mgr, uprobe, signature, args, &flow_def); if (unlikely(!upipe)) { return NULL; } upipe_vblk_init_urefcount(upipe); upipe_vblk_init_output(upipe); upipe_vblk_init_flow_def(upipe); upipe_vblk_init_ubuf_mgr(upipe); struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe); upipe_vblk->ubuf = NULL; upipe_throw_ready(upipe); if (unlikely(!ubase_check(upipe_vblk_check_flow_def(upipe, flow_def)))) { uref_free(flow_def); upipe_release(upipe); return NULL; } upipe_vblk_store_flow_def(upipe, flow_def); return upipe; }
/** @This is called when there is no external reference to the pipe anymore. * * @param upipe description structure of the pipe */ static void upipe_wsrc_no_ref(struct upipe *upipe) { struct upipe_wsrc *upipe_wsrc = upipe_wsrc_from_upipe(upipe); upipe_release(upipe_wsrc->source); upipe_wsrc->source = NULL; upipe_wsrc_clean_bin_output(upipe); urefcount_release(upipe_wsrc_to_urefcount_real(upipe_wsrc)); }
/** @internal @This flushes all currently held buffers, and unblocks the * sources. * * @param upipe description structure of the pipe * @return an error code */ static int upipe_fsink_flush(struct upipe *upipe) { if (upipe_fsink_flush_input(upipe)) { upipe_fsink_set_upump(upipe, NULL); /* All packets have been output, release again the pipe that has been * used in @ref upipe_fsink_input. */ upipe_release(upipe); } return UBASE_ERR_NONE; }
/** split callback */ static int split_catch(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { if (event != UPROBE_NEED_OUTPUT) return uprobe_throw_next(uprobe, upipe, event, args); upipe_release(upipe_split_output); upipe_split_output = upipe_use(upipe); struct upipe *avcdec = upipe_void_alloc_output(upipe, upipe_avcdec_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_avcdec), loglevel, "avcdec")); if (avcdec == NULL) { upipe_err_va(upipe, "incompatible flow def"); upipe_release(upipe_source); return UBASE_ERR_UNHANDLED; } upipe_release(avcdec); return UBASE_ERR_NONE; }
/** @internal @This is called when the file descriptor can be written again. * Unblock the sink and unqueue all queued buffers. * * @param upump description structure of the watcher */ static void upipe_fsink_watcher(struct upump *upump) { struct upipe *upipe = upump_get_opaque(upump, struct upipe *); upipe_fsink_set_upump(upipe, NULL); upipe_fsink_output_input(upipe); upipe_fsink_unblock_input(upipe); if (upipe_fsink_check_input(upipe)) { /* All packets have been output, release again the pipe that has been * used in @ref upipe_fsink_input. */ upipe_release(upipe); } }
/** @internal @This handles inner reader pipe events. * * @param uprobe structure used to raise events * @param inner pointer to inner pipe * @param event event thrown * @param args optional arguments * @return an error code */ static int probe_reader(struct uprobe *uprobe, struct upipe *inner, int event, va_list args) { struct upipe_hls *upipe_hls = upipe_hls_from_probe_reader(uprobe); struct upipe *upipe = upipe_hls_to_upipe(upipe_hls); if (event >= UPROBE_LOCAL) return UBASE_ERR_NONE; if (event == UPROBE_NEED_OUTPUT) { struct uref *flow_format = va_arg(args, struct uref *); const char *def; UBASE_RETURN(uref_flow_get_def(flow_format, &def)); struct uref *flow_format_dup = uref_dup(flow_format); if (unlikely(!flow_format_dup)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } upipe_hls_store_flow_def(upipe, flow_format_dup); if (!strcmp(def, "block.m3u.playlist.")) { struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc(); struct upipe *output = upipe_void_alloc_output( inner, upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_null), UPROBE_LOG_VERBOSE, "null")); upipe_mgr_release(upipe_null_mgr); upipe_release(output); upipe_split_throw_update(upipe); return UBASE_ERR_NONE; } else if (!strcmp(def, "block.m3u.master.")) { struct upipe_mgr *upipe_hls_master_mgr = upipe_hls_master_mgr_alloc(); UBASE_ALLOC_RETURN(upipe_hls_master_mgr); struct upipe *output = upipe_void_alloc_output( inner, upipe_hls_master_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_master), UPROBE_LOG_VERBOSE, "master")); upipe_mgr_release(upipe_hls_master_mgr); UBASE_ALLOC_RETURN(output); upipe_hls_store_bin_output(upipe, output); return UBASE_ERR_NONE; } else upipe_warn_va(upipe, "unsupported flow format %s", def); return UBASE_ERR_INVALID; } return upipe_throw_proxy(upipe, inner, event, args); }
/** @internal @This catches events of the glx pipe. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_glx(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_GLX_SINK_KEYPRESS: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_glx_s); unsigned int signature = va_arg(args, unsigned int); assert(signature == UPIPE_GLX_SINK_SIGNATURE); unsigned long key = va_arg(args, unsigned long); switch (key) { case 27: case 'q': { upipe_notice_va(upipe, "exit key pressed (%d), exiting", key); upipe_release(glxplayer->upipe_src_xfer); upipe_mgr_release(glxplayer->src_xfer); break; } case ' ': { if (glxplayer->trickp) { if ( (glxplayer->paused = !glxplayer->paused) ) { upipe_notice(upipe, "Playback paused"); struct urational rate = { .num = 0, .den = 0 }; upipe_trickp_set_rate(glxplayer->upipe_trickp, rate); } else { upipe_notice(upipe, "Playback resumed"); struct urational rate = { .num = 1, .den = 1 }; upipe_trickp_set_rate(glxplayer->upipe_trickp, rate); } } break; } default: upipe_dbg_va(upipe, "key pressed (%d)", key); break; } return UBASE_ERR_NONE; } case UPROBE_GLX_SINK_KEYRELEASE: return UBASE_ERR_NONE; default: break; } return uprobe_throw_next(uprobe, upipe, event, args); }
static int upipe_s337_encaps_check(struct upipe *upipe, struct uref *flow_format) { if (flow_format != NULL) upipe_s337_encaps_store_flow_def(upipe, flow_format); bool was_buffered = !upipe_s337_encaps_check_input(upipe); upipe_s337_encaps_output_input(upipe); upipe_s337_encaps_unblock_input(upipe); if (was_buffered && upipe_s337_encaps_check_input(upipe)) { /* All packets have been output, release again the pipe that has been * used in @ref upipe_s337_encaps_input. */ upipe_release(upipe); } return UBASE_ERR_NONE; }
/** @internal @This sets the input flow definition. * * @param upipe description structure of the pipe * @param flow_def flow definition packet * @return an error code */ static int upipe_fdec_set_flow_def(struct upipe *upipe, struct uref *flow_def) { struct upipe_fdec_mgr *fdec_mgr = upipe_fdec_mgr_from_upipe_mgr(upipe->mgr); struct upipe_fdec *upipe_fdec = upipe_fdec_from_upipe(upipe); if (flow_def == NULL) return UBASE_ERR_INVALID; if (upipe_fdec->last_inner != NULL) { if (ubase_check(upipe_set_flow_def(upipe_fdec->last_inner, flow_def))) return UBASE_ERR_NONE; } upipe_fdec_store_bin_input(upipe, NULL); upipe_fdec_store_bin_output(upipe, NULL); struct upipe *avcdec = upipe_void_alloc(fdec_mgr->avcdec_mgr, uprobe_pfx_alloc( uprobe_use(&upipe_fdec->last_inner_probe), UPROBE_LOG_VERBOSE, "avcdec")); if (unlikely(avcdec == NULL)) { upipe_err_va(upipe, "couldn't allocate avcdec"); return UBASE_ERR_UNHANDLED; } if (unlikely(!ubase_check(upipe_set_flow_def(avcdec, flow_def)))) { upipe_err_va(upipe, "couldn't set avcdec flow def"); upipe_release(avcdec); return UBASE_ERR_UNHANDLED; } if (upipe_fdec->options != NULL && upipe_fdec->options->udict != NULL) { const char *key = NULL; enum udict_type type = UDICT_TYPE_END; while (ubase_check(udict_iterate(upipe_fdec->options->udict, &key, &type)) && type != UDICT_TYPE_END) { const char *value; if (key == NULL || !ubase_check(udict_get_string(upipe_fdec->options->udict, &value, type, key))) continue; if (!ubase_check(upipe_set_option(avcdec, key, value))) upipe_warn_va(upipe, "option %s=%s invalid", key, value); } } upipe_fdec_store_bin_input(upipe, upipe_use(avcdec)); upipe_fdec_store_bin_output(upipe, avcdec); return UBASE_ERR_NONE; }
/** @internal @This checks if the input may start. * * @param upipe description structure of the pipe * @param flow_format amended flow format * @return an error code */ static int upipe_filter_blend_check(struct upipe *upipe, struct uref *flow_format) { struct upipe_filter_blend *upipe_filter_blend = upipe_filter_blend_from_upipe(upipe); if (flow_format != NULL) upipe_filter_blend_store_flow_def(upipe, flow_format); if (upipe_filter_blend->flow_def == NULL) return UBASE_ERR_NONE; bool was_buffered = !upipe_filter_blend_check_input(upipe); upipe_filter_blend_output_input(upipe); upipe_filter_blend_unblock_input(upipe); if (was_buffered && upipe_filter_blend_check_input(upipe)) { /* All packets have been output, release again the pipe that has been * used in @ref upipe_filter_blend_input. */ upipe_release(upipe); } return UBASE_ERR_NONE; }
/** @internal @This provides a ubuf_mgr request. * * @param upipe description structure of the pipe * @param flow_format amended flow format * @return an error code */ static int upipe_audiobar_check_ubuf_mgr(struct upipe *upipe, struct uref *flow_format) { struct upipe_audiobar *upipe_audiobar = upipe_audiobar_from_upipe(upipe); if (flow_format == NULL) return UBASE_ERR_NONE; upipe_audiobar_store_flow_def(upipe, flow_format); UBASE_RETURN(uref_pic_flow_get_hsize(flow_format, &upipe_audiobar->hsize)) UBASE_RETURN(uref_pic_flow_get_vsize(flow_format, &upipe_audiobar->vsize)) upipe_audiobar->chan_width = upipe_audiobar->hsize / upipe_audiobar->channels; upipe_audiobar->chan_width -= upipe_audiobar->chan_width % 2; if (unlikely(upipe_audiobar->chan_width < 16)) { upipe_warn_va(upipe, "channel width is too small to have a separation (%"PRIu64")", upipe_audiobar->chan_width); } upipe_audiobar->sep_width = upipe_audiobar->chan_width / 4; upipe_audiobar->sep_width -= upipe_audiobar->sep_width % 4; upipe_audiobar->pad_width = upipe_audiobar->hsize - upipe_audiobar->chan_width * upipe_audiobar->channels; upipe_notice_va(upipe, "setting up chan %"PRIu64" sep %"PRIu64" pad %"PRIu64, upipe_audiobar->chan_width, upipe_audiobar->sep_width, upipe_audiobar->pad_width); bool was_buffered = !upipe_audiobar_check_input(upipe); upipe_audiobar_output_input(upipe); upipe_audiobar_unblock_input(upipe); if (was_buffered && upipe_audiobar_check_input(upipe)) { /* All packets have been output, release again the pipe that has been * used in @ref upipe_audiobar_input. */ upipe_release(upipe); } return UBASE_ERR_NONE; }
/** @internal @This outputs the m3u. * * @param upipe description structure of the pipe * @param upump_p reference to source pump to block */ static void upipe_m3u_reader_output_all(struct upipe *upipe, struct upump **upump_p) { struct upipe_m3u_reader *upipe_m3u_reader = upipe_m3u_reader_from_upipe(upipe); struct uref *flow_def = upipe_m3u_reader->current_flow_def; upipe_m3u_reader->current_flow_def = NULL; if (unlikely(!ubase_check(uref_flow_match_def(flow_def, M3U_FLOW_DEF)))) { upipe_err(upipe, "invalid m3u"); uref_free(flow_def); return; } /* force new flow def */ upipe_m3u_reader_store_flow_def(upipe, NULL); /* set output flow def */ upipe_m3u_reader_store_flow_def(upipe, flow_def); /* output */ struct uchain *uchain; bool first = true; upipe_use(upipe); while ((uchain = ulist_pop(&upipe_m3u_reader->items)) != NULL) { struct uref *uref = uref_from_uchain(uchain); if (first) uref_block_set_start(uref); first = false; if (ulist_empty(&upipe_m3u_reader->items)) uref_block_set_end(uref); upipe_m3u_reader_output(upipe, uref, upump_p); } upipe_release(upipe); }
/** @This starts playing the given URI. * * @param glxplayer glxplayer context * @param upump_mgr upump manager of the main thread * @param uri URI to play * @param upipe_ts set to true to use Upipe's TS demux, false for libavformat * @return false in case of error */ static bool upipe_glxplayer_play(struct upipe_glxplayer *glxplayer, struct upump_mgr *upump_mgr, const char *uri, bool upipe_ts) { struct upipe *upipe_src; uprobe_pthread_upump_mgr_set(glxplayer->uprobe_logger, upump_mgr); uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_FREEZE_UPUMP_MGR); if (!upipe_ts) { /* use avformat source (and internal demuxer) */ struct upipe_mgr *upipe_avfsrc_mgr = upipe_avfsrc_mgr_alloc(); if (unlikely(upipe_avfsrc_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_avfsrc_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_selflow), glxplayer->loglevel, "avfsrc")); upipe_mgr_release(upipe_avfsrc_mgr); if (unlikely(upipe_src == NULL)) return false; if (unlikely(!ubase_check(upipe_attach_uclock(upipe_src)) || !ubase_check(upipe_set_uri(upipe_src, uri)))) { upipe_release(upipe_src); return false; } glxplayer->trickp = true; } else { /* try file source */ struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc(); if (unlikely(upipe_fsrc_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_fsrc_mgr, uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s), glxplayer->loglevel, "fsrc")); upipe_mgr_release(upipe_fsrc_mgr); if (unlikely(upipe_src == NULL)) return false; if (ubase_check(upipe_set_uri(upipe_src, uri))) { glxplayer->trickp = true; } else { upipe_release(upipe_src); glxplayer->trickp = false; /* try udp source */ struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); if (unlikely(upipe_udpsrc_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_udpsrc_mgr, uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s), glxplayer->loglevel, "udpsrc")); upipe_mgr_release(upipe_udpsrc_mgr); if (unlikely(upipe_src == NULL)) return false; if (ubase_check(upipe_set_uri(upipe_src, uri))) { upipe_attach_uclock(upipe_src); } else { upipe_release(upipe_src); /* try http source */ struct upipe_mgr *upipe_http_src_mgr = upipe_http_src_mgr_alloc(); if (unlikely(upipe_http_src_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_http_src_mgr, uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s), glxplayer->loglevel, "httpsrc")); upipe_mgr_release(upipe_http_src_mgr); if (unlikely(upipe_src == NULL)) return false; if (!ubase_check(upipe_set_uri(upipe_src, uri))) { upipe_release(upipe_src); return false; } } } /* upipe-ts demuxer */ struct upipe_mgr *upipe_ts_demux_mgr = upipe_ts_demux_mgr_alloc(); if (unlikely(upipe_ts_demux_mgr == NULL)) { upipe_release(upipe_src); return false; } struct upipe_mgr *upipe_mpgvf_mgr = upipe_mpgvf_mgr_alloc(); if (upipe_mpgvf_mgr != NULL) { upipe_ts_demux_mgr_set_mpgvf_mgr(upipe_ts_demux_mgr, upipe_mpgvf_mgr); upipe_mgr_release(upipe_mpgvf_mgr); } struct upipe_mgr *upipe_h264f_mgr = upipe_h264f_mgr_alloc(); if (upipe_h264f_mgr != NULL) { upipe_ts_demux_mgr_set_h264f_mgr(upipe_ts_demux_mgr, upipe_h264f_mgr); upipe_mgr_release(upipe_h264f_mgr); } struct upipe *upipe_ts_demux = upipe_void_alloc_output(upipe_src, upipe_ts_demux_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_selprog), glxplayer->loglevel, "ts demux")); if (unlikely(upipe_ts_demux == NULL)) { upipe_mgr_release(upipe_ts_demux_mgr); upipe_release(upipe_src); return false; } upipe_release(upipe_ts_demux); upipe_mgr_release(upipe_ts_demux_mgr); } if (!glxplayer->trickp) uprobe_dejitter_set(glxplayer->uprobe_dejitter, true, 0); /* prepare a queue source for the decoded video frames */ uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_THAW_UPUMP_MGR); glxplayer->upipe_glx_qsrc = upipe_qsrc_alloc(glxplayer->upipe_qsrc_mgr, uprobe_pfx_alloc( uprobe_use(&glxplayer->uprobe_glx_qsrc_s), glxplayer->loglevel, "glx qsrc"), GLX_QUEUE_LENGTH); if (unlikely(glxplayer->upipe_glx_qsrc == NULL)) { upipe_release(upipe_src); return false; } upipe_attach_upump_mgr(glxplayer->upipe_glx_qsrc); /* prepare to transfer the source to a new thread */ glxplayer->src_xfer = upipe_xfer_mgr_alloc(XFER_QUEUE, XFER_POOL); if (unlikely(glxplayer->src_xfer == NULL)) { upipe_release(upipe_src); upipe_release(glxplayer->upipe_glx_qsrc); return false; } /* spawn a thread for the source */ if (pthread_create(&glxplayer->src_thread_id, NULL, upipe_glxplayer_source_thread, glxplayer)) { upipe_mgr_release(glxplayer->src_xfer); upipe_release(glxplayer->upipe_glx_qsrc); return false; } glxplayer->upipe_src_xfer = upipe_xfer_alloc(glxplayer->src_xfer, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "source xfer"), upipe_src); if (unlikely(glxplayer->upipe_src_xfer == NULL)) { upipe_mgr_release(glxplayer->src_xfer); upipe_release(upipe_src); upipe_release(glxplayer->upipe_glx_qsrc); return false; } /* from now on upipe_src should not be accessed */ upipe_attach_upump_mgr(glxplayer->upipe_src_xfer); glxplayer->upipe_ts = upipe_ts; glxplayer->uri = strdup(uri); return true; }
/** @internal @This allocates a wsrc pipe. * * @param mgr common management structure * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to upipe or NULL in case of allocation error */ static struct upipe *_upipe_wsrc_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct upipe_wsrc_mgr *wsrc_mgr = upipe_wsrc_mgr_from_upipe_mgr(mgr); if (unlikely(signature != UPIPE_WSRC_SIGNATURE || wsrc_mgr->xfer_mgr == NULL)) goto upipe_wsrc_alloc_err; struct upipe *remote = va_arg(args, struct upipe *); struct uprobe *uprobe_remote = va_arg(args, struct uprobe *); unsigned int queue_length = va_arg(args, unsigned int); assert(queue_length); if (unlikely(remote == NULL)) goto upipe_wsrc_alloc_err2; struct upipe_wsrc *upipe_wsrc = malloc(sizeof(struct upipe_wsrc)); if (unlikely(upipe_wsrc == NULL)) goto upipe_wsrc_alloc_err2; struct upipe *upipe = upipe_wsrc_to_upipe(upipe_wsrc); upipe_init(upipe, mgr, uprobe); upipe_wsrc_init_urefcount(upipe); urefcount_init(upipe_wsrc_to_urefcount_real(upipe_wsrc), upipe_wsrc_free); upipe_wsrc_init_last_inner_probe(upipe); upipe_wsrc_init_bin_output(upipe); upipe_wsrc->source = NULL; uprobe_init(&upipe_wsrc->proxy_probe, upipe_wsrc_proxy_probe, NULL); upipe_wsrc->proxy_probe.refcount = upipe_wsrc_to_urefcount_real(upipe_wsrc); uprobe_init(&upipe_wsrc->qsrc_probe, upipe_wsrc_qsrc_probe, &upipe_wsrc->last_inner_probe); upipe_wsrc->qsrc_probe.refcount = upipe_wsrc_to_urefcount_real(upipe_wsrc); upipe_throw_ready(upipe); /* output queue */ struct upipe *out_qsrc = upipe_qsrc_alloc(wsrc_mgr->qsrc_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_wsrc->qsrc_probe), UPROBE_LOG_VERBOSE, "out_qsrc"), queue_length > UINT8_MAX ? UINT8_MAX : queue_length); if (unlikely(out_qsrc == NULL)) goto upipe_wsrc_alloc_err3; struct upipe *out_qsink = upipe_qsink_alloc(wsrc_mgr->qsink_mgr, uprobe_pfx_alloc(uprobe_remote, UPROBE_LOG_VERBOSE, "out_qsink"), out_qsrc); if (unlikely(out_qsink == NULL)) { upipe_release(out_qsrc); goto upipe_wsrc_alloc_err3; } if (queue_length > UINT8_MAX) upipe_set_max_length(out_qsink, queue_length - UINT8_MAX); upipe_attach_upump_mgr(out_qsrc); upipe_wsrc_store_bin_output(upipe, out_qsrc); /* last remote */ struct upipe *last_remote = upipe_use(remote); struct upipe *tmp; /* upipe_get_output is a control command and may trigger a need_upump_mgr * event */ uprobe_throw(upipe->uprobe, NULL, UPROBE_FREEZE_UPUMP_MGR); while (ubase_check(upipe_get_output(last_remote, &tmp)) && tmp != NULL) { upipe_use(tmp); upipe_release(last_remote); last_remote = tmp; } uprobe_throw(upipe->uprobe, NULL, UPROBE_THAW_UPUMP_MGR); struct upipe *last_remote_xfer = upipe_xfer_alloc(wsrc_mgr->xfer_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_wsrc->proxy_probe), UPROBE_LOG_VERBOSE, "src_last_xfer"), last_remote); if (unlikely(last_remote_xfer == NULL)) { upipe_release(out_qsink); goto upipe_wsrc_alloc_err3; } upipe_attach_upump_mgr(last_remote_xfer); upipe_set_output(last_remote_xfer, out_qsink); upipe_release(out_qsink); /* remote */ if (last_remote != remote) { upipe_wsrc->source = upipe_xfer_alloc(wsrc_mgr->xfer_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_wsrc->proxy_probe), UPROBE_LOG_VERBOSE, "src_xfer"), remote); if (unlikely(upipe_wsrc->source == NULL)) { upipe_release(out_qsink); upipe_release(upipe); return NULL; } upipe_attach_upump_mgr(upipe_wsrc->source); upipe_release(last_remote_xfer); } else { upipe_wsrc->source = last_remote_xfer; upipe_release(remote); } return upipe; upipe_wsrc_alloc_err3: upipe_release(remote); upipe_release(upipe); return NULL; upipe_wsrc_alloc_err2: uprobe_release(uprobe_remote); upipe_release(remote); upipe_wsrc_alloc_err: uprobe_release(uprobe); return NULL; }
/** @internal @This configures a new codec context * * @param upipe description structure of the pipe * @param codec avcodec description structure * @param extradata pointer to extradata buffer * @param extradata_size extradata size * @return false if the buffer couldn't be accepted */ static bool upipe_avcdec_open_codec(struct upipe *upipe, AVCodec *codec, uint8_t *extradata, int extradata_size) { AVCodecContext *context = NULL; struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe); assert(upipe); /* close previously opened context */ if (unlikely(upipe_avcdec->context)) { /* first send empty packet to flush retained frames */ upipe_dbg(upipe, "flushing frames in decoder"); while (upipe_avcdec_process_buf(upipe, NULL, 0, NULL)); /* now close codec and free extradata if any */ upipe_notice_va(upipe, "avcodec context (%s) closed (%d)", upipe_avcdec->context->codec->name, upipe_avcdec->counter); avcodec_close(upipe_avcdec->context); if (upipe_avcdec->context->extradata_size > 0) { free(upipe_avcdec->context->extradata); } av_free(upipe_avcdec->context); upipe_avcdec->context = NULL; upipe_avcdec_store_flow_def(upipe, NULL); } /* just closing, that's all */ if (!codec) { upipe_release(upipe); return false; } /* allocate and configure codec context */ context = avcodec_alloc_context3(codec); if (unlikely(!context)) { upipe_throw_aerror(upipe); upipe_release(upipe); return false; } context->opaque = upipe; context->extradata = extradata; context->extradata_size = extradata_size; switch (codec->type) { case AVMEDIA_TYPE_VIDEO: { if (upipe_avcdec->lowres > codec->max_lowres) { upipe_warn_va(upipe, "Unsupported lowres (%d > %hhu), setting to %hhu", upipe_avcdec->lowres, codec->max_lowres, codec->max_lowres); upipe_avcdec->lowres = codec->max_lowres; } context->get_buffer = upipe_avcdec_get_buffer; context->release_buffer = upipe_avcdec_release_buffer; context->flags |= CODEC_FLAG_EMU_EDGE; context->lowres = upipe_avcdec->lowres; context->skip_loop_filter = AVDISCARD_ALL; break; } case AVMEDIA_TYPE_AUDIO: { context->get_buffer = upipe_avcdec_get_buffer_audio; break; } default: { av_free(context); upipe_err_va(upipe, "Unsupported media type (%d)", codec->type); upipe_release(upipe); return false; break; } } /* open new context */ if (unlikely(avcodec_open2(context, codec, NULL) < 0)) { upipe_warn(upipe, "could not open codec"); av_free(context); upipe_release(upipe); return false; } upipe_avcdec->context = context; upipe_avcdec->counter = 0; upipe_notice_va(upipe, "codec %s (%s) %d opened", codec->name, codec->long_name, codec->id); upipe_release(upipe); return true; }
/** @internal @This allocates a blank source pipe. * * @param mgr common management structure * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to upipe or NULL in case of allocation error */ static struct upipe *upipe_blksrc_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct uref *flow_def; struct upipe *upipe = upipe_blksrc_alloc_flow(mgr, uprobe, signature, args, &flow_def); if (unlikely(!upipe)) { return NULL; } struct upipe_blksrc *upipe_blksrc = upipe_blksrc_from_upipe(upipe); upipe_blksrc_init_urefcount(upipe); upipe_blksrc_init_urefcount_real(upipe); upipe_blksrc_init_src_probe(upipe); upipe_blksrc_init_blk_probe(upipe); upipe_blksrc_init_bin_input(upipe); upipe_blksrc_init_bin_output(upipe); upipe_blksrc->flow_def = flow_def; upipe_throw_ready(upipe); uint64_t duration = 0; if (ubase_check(uref_flow_match_def(flow_def, UREF_PIC_FLOW_DEF))) { struct urational fps; if (unlikely(!ubase_check(uref_pic_flow_get_fps(flow_def, &fps)))) { upipe_release(upipe); return NULL; } duration = (uint64_t)UCLOCK_FREQ * fps.den / fps.num; } else if (ubase_check(uref_flow_match_def(flow_def, UREF_SOUND_FLOW_DEF))) { uint64_t samples, rate; if (unlikely(!ubase_check(uref_sound_flow_get_samples(flow_def, &samples))) || unlikely(!ubase_check(uref_sound_flow_get_rate(flow_def, &rate)))) { upipe_release(upipe); return NULL; } duration = samples * UCLOCK_FREQ / rate; } else { upipe_warn(upipe, "unsupported flow def"); upipe_release(upipe); return NULL; } struct uref *src_flow_def = uref_void_flow_alloc_def(flow_def->mgr); if (unlikely(!src_flow_def)) { upipe_err(upipe, "fail to allocate source pipe flow def"); upipe_release(upipe); return NULL; } if (unlikely(!ubase_check(uref_clock_set_duration(src_flow_def, duration)))) { uref_free(src_flow_def); upipe_release(upipe); return NULL; } struct upipe_mgr *upipe_voidsrc_mgr = upipe_voidsrc_mgr_alloc(); if (unlikely(!upipe_voidsrc_mgr)) { upipe_err(upipe, "fail to get void source manager"); uref_free(src_flow_def); upipe_release(upipe); return NULL; } struct upipe *src = upipe_flow_alloc(upipe_voidsrc_mgr, uprobe_pfx_alloc( uprobe_use(&upipe_blksrc->src_probe), UPROBE_LOG_VERBOSE, "src"), src_flow_def); upipe_mgr_release(upipe_voidsrc_mgr); uref_free(src_flow_def); if (unlikely(!src)) { upipe_err(upipe, "fail to allocate source pipe"); upipe_release(upipe); return NULL; } upipe_blksrc_store_bin_input(upipe, src); struct upipe_mgr *upipe_blk_mgr = NULL; if (ubase_check(uref_flow_match_def(flow_def, UREF_PIC_FLOW_DEF))) { upipe_blk_mgr = upipe_vblk_mgr_alloc(); } else if (ubase_check(uref_flow_match_def(flow_def, UREF_SOUND_FLOW_DEF))) { upipe_blk_mgr = upipe_ablk_mgr_alloc(); } if (unlikely(!upipe_blk_mgr)) { upipe_err(upipe, "fail to get blank generator manager"); upipe_release(upipe); return NULL; } struct upipe *blk = upipe_flow_alloc(upipe_blk_mgr, uprobe_pfx_alloc( uprobe_use(&upipe_blksrc->blk_probe), UPROBE_LOG_VERBOSE, "blk"), flow_def); upipe_mgr_release(upipe_blk_mgr); if (unlikely(!blk)) { upipe_err(upipe, "fail to allocate blank generator pipe"); upipe_release(upipe); return NULL; } upipe_blksrc_store_bin_output(upipe, blk); if (unlikely(!ubase_check(upipe_set_output(src, blk)))) { upipe_release(upipe); return NULL; } return upipe; }
int main(int argc, char **argv) { int opt; /* parse options */ while ((opt = getopt(argc, argv, "dqD:")) != -1) { switch (opt) { case 'd': if (loglevel > 0) loglevel--; break; case 'q': if (loglevel < UPROBE_LOG_ERROR) loglevel++; break; case 'D': dump = optarg; break; default: usage(argv[0]); } } if (optind >= argc - 1) { usage(argv[0]); } srcpath = argv[optind++]; dstpath = argv[optind++]; /* choose log fd */ logstream = stderr; /* setup environnement */ struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH, umem_mgr, -1, -1); uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, 0); struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); /* default probe */ logger = uprobe_stdio_alloc(NULL, logstream, loglevel); assert(logger != NULL); logger = uprobe_uref_mgr_alloc(logger, uref_mgr); assert(logger != NULL); logger = uprobe_upump_mgr_alloc(logger, upump_mgr); assert(logger != NULL); logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH, UBUF_POOL_DEPTH); assert(logger != NULL); uref_mgr_release(uref_mgr); upump_mgr_release(upump_mgr); /* split probe */ struct uprobe uprobe_catch; uprobe_init(&uprobe_catch, split_catch, uprobe_use(logger)); /* other probes */ uprobe_init(&uprobe_avcdec, avcdec_catch, uprobe_use(logger)); uprobe_init(&uprobe_uref, uref_catch, uprobe_use(logger)); /* upipe-av */ upipe_av_init(true, uprobe_use(logger)); /* global pipe managers */ upipe_avcdec_mgr = upipe_avcdec_mgr_alloc(); upipe_avcenc_mgr = upipe_avcenc_mgr_alloc(); upipe_sws_mgr = upipe_sws_mgr_alloc(); upipe_filter_blend_mgr = upipe_filter_blend_mgr_alloc(); upipe_fsink_mgr = upipe_fsink_mgr_alloc(); upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); /* null */ struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc(); upipe_null = upipe_void_alloc(upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "null")); assert(upipe_null != NULL); upipe_mgr_release(upipe_null_mgr); /* file source */ struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc(); upipe_source = upipe_void_alloc(upipe_fsrc_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "fsrc")); assert(upipe_source != NULL); upipe_mgr_release(upipe_fsrc_mgr); if (!ubase_check(upipe_set_uri(upipe_source, srcpath))) exit(EXIT_FAILURE); /* upipe-ts */ struct upipe_mgr *upipe_ts_demux_mgr = upipe_ts_demux_mgr_alloc(); struct upipe_mgr *upipe_autof_mgr = upipe_autof_mgr_alloc(); upipe_ts_demux_mgr_set_autof_mgr(upipe_ts_demux_mgr, upipe_autof_mgr); upipe_mgr_release(upipe_autof_mgr); struct upipe *ts_demux = upipe_void_alloc_output(upipe_source, upipe_ts_demux_mgr, uprobe_pfx_alloc( uprobe_selflow_alloc(uprobe_use(logger), uprobe_selflow_alloc(uprobe_use(logger), &uprobe_catch, UPROBE_SELFLOW_PIC, "auto"), UPROBE_SELFLOW_VOID, "auto"), loglevel, "tsdemux")); assert(ts_demux != NULL); upipe_mgr_release(upipe_ts_demux_mgr); upipe_release(ts_demux); /* fire loop ! */ upump_mgr_run(upump_mgr, NULL); /* release everyhing */ upipe_release(upipe_source); upipe_release(upipe_split_output); upipe_release(upipe_null); uprobe_release(logger); uprobe_clean(&uprobe_catch); uprobe_clean(&uprobe_avcdec); uprobe_clean(&uprobe_uref); upipe_mgr_release(upipe_avcdec_mgr); upipe_mgr_release(upipe_avcenc_mgr); upipe_mgr_release(upipe_sws_mgr); upipe_mgr_release(upipe_filter_blend_mgr); upipe_mgr_release(upipe_fsink_mgr); upipe_mgr_release(upipe_probe_uref_mgr); udict_mgr_release(udict_mgr); umem_mgr_release(umem_mgr); upipe_av_clean(); return 0; }
/** avcdec callback */ static int avcdec_catch(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { if (event != UPROBE_NEED_OUTPUT) return uprobe_throw_next(uprobe, upipe, event, args); struct uref *flow_def = va_arg(args, struct uref *); uint64_t hsize, vsize, wanted_hsize; struct urational sar; bool progressive; if (unlikely(!ubase_check(uref_pic_flow_get_hsize(flow_def, &hsize)) || !ubase_check(uref_pic_flow_get_vsize(flow_def, &vsize)) || !ubase_check(uref_pic_flow_get_sar(flow_def, &sar)))) { upipe_err_va(upipe, "incompatible flow def"); upipe_release(upipe_source); return UBASE_ERR_UNHANDLED; } wanted_hsize = (hsize * sar.num / sar.den / 2) * 2; progressive = ubase_check(uref_pic_get_progressive(flow_def)); struct uref *flow_def2 = uref_dup(flow_def); upipe_use(upipe); if (!progressive) { uref_pic_set_progressive(flow_def2); struct upipe *deint = upipe_void_alloc_output(upipe, upipe_filter_blend_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "deint")); assert(deint != NULL); upipe_release(upipe); upipe = deint; } if (wanted_hsize != hsize) { uref_pic_flow_set_hsize(flow_def2, wanted_hsize); struct upipe *sws = upipe_flow_alloc_output(upipe, upipe_sws_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "sws"), flow_def2); assert(sws != NULL); upipe_release(upipe); upipe = sws; } uref_pic_flow_clear_format(flow_def2); uref_flow_set_def(flow_def2, "block.mjpeg.pic."); struct upipe *jpegenc = upipe_flow_alloc_output(upipe, upipe_avcenc_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "jpeg"), flow_def2); assert(jpegenc != NULL); upipe_release(upipe); upipe_set_option(jpegenc, "qmax", "2"); upipe = jpegenc; struct upipe *urefprobe = upipe_void_alloc_output(upipe, upipe_probe_uref_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_uref), loglevel, "urefprobe")); assert(urefprobe != NULL); upipe_release(upipe); upipe = urefprobe; struct upipe *fsink = upipe_void_alloc_output(upipe, upipe_fsink_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), ((loglevel > UPROBE_LOG_DEBUG) ? UPROBE_LOG_WARNING : loglevel), "jpegsink")); assert(fsink != NULL); upipe_release(upipe); upipe_fsink_set_path(fsink, dstpath, UPIPE_FSINK_OVERWRITE); upipe = fsink; uref_free(flow_def2); upipe_release(upipe); return UBASE_ERR_NONE; }
int main(int argc, char *argv[]) { assert(argc >= 2); nb_files = argc - 1; files = argv + 1; struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); assert(upump_mgr != NULL); struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); assert(umem_mgr != NULL); struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH, umem_mgr, -1, -1); assert(udict_mgr != NULL); struct uref_mgr *uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, 0); /* main probe */ struct uprobe *logger = uprobe_stdio_alloc(NULL, stderr, UPROBE_LOG_VERBOSE); assert(logger != NULL); logger = uprobe_uref_mgr_alloc(logger, uref_mgr); assert(logger != NULL); logger = uprobe_upump_mgr_alloc(logger, upump_mgr); assert(logger != NULL); logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH, UBUF_POOL_DEPTH); assert(logger != NULL); /* file source */ struct uprobe uprobe_fsrc; uprobe_init(&uprobe_fsrc, catch_fsrc, uprobe_use(logger)); struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc(); assert(upipe_fsrc_mgr != NULL); struct upipe *upipe_fsrc = upipe_void_alloc(upipe_fsrc_mgr, uprobe_pfx_alloc(uprobe_use(&uprobe_fsrc), UPROBE_LOG_DEBUG, "file source")); assert(upipe_fsrc != NULL); upipe_mgr_release(upipe_fsrc_mgr); ubase_assert(upipe_set_uri(upipe_fsrc, files[current])); /* m3u reader */ struct upipe_mgr *upipe_m3u_reader_mgr = upipe_m3u_reader_mgr_alloc(); assert(upipe_m3u_reader_mgr != NULL); struct upipe *upipe_m3u_reader = upipe_void_alloc_output( upipe_fsrc, upipe_m3u_reader_mgr, uprobe_pfx_alloc(uprobe_use(logger), UPROBE_LOG_VERBOSE, "m3u reader")); upipe_mgr_release(upipe_m3u_reader_mgr); assert(upipe_m3u_reader != NULL); struct uprobe uprobe_uref; uprobe_init(&uprobe_uref, catch_uref, uprobe_use(logger)); struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); assert(upipe_probe_uref_mgr != NULL); struct upipe *upipe_probe_uref = upipe_void_chain_output( upipe_m3u_reader, upipe_probe_uref_mgr, uprobe_pfx_alloc(uprobe_use(&uprobe_uref), UPROBE_LOG_DEBUG, "probe uref")); upipe_mgr_release(upipe_probe_uref_mgr); assert(upipe_probe_uref != NULL); /* null output */ struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc(); assert(upipe_null_mgr != NULL); struct upipe *upipe_null = upipe_void_chain_output( upipe_probe_uref, upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(logger), UPROBE_LOG_DEBUG, "null")); upipe_mgr_release(upipe_null_mgr); assert(upipe_null != NULL); upipe_release(upipe_null); /* run main loop */ upump_mgr_run(upump_mgr, NULL); /* release */ upipe_release(upipe_fsrc); upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); udict_mgr_release(udict_mgr); umem_mgr_release(umem_mgr); uprobe_clean(&uprobe_fsrc); uprobe_clean(&uprobe_uref); uprobe_release(logger); return 0; }
/** @internal @This asks to open the given file. * * @param upipe description structure of the pipe * @param path relative or absolute path of the file * @param mode mode of opening the file * @return an error code */ static int _upipe_fsink_set_path(struct upipe *upipe, const char *path, enum upipe_fsink_mode mode) { struct upipe_fsink *upipe_fsink = upipe_fsink_from_upipe(upipe); if (unlikely(upipe_fsink->fd != -1)) { if (likely(upipe_fsink->path != NULL)) upipe_notice_va(upipe, "closing file %s", upipe_fsink->path); close(upipe_fsink->fd); } free(upipe_fsink->path); upipe_fsink->path = NULL; upipe_fsink_set_upump(upipe, NULL); if (!upipe_fsink_check_input(upipe)) /* Release the pipe used in @ref upipe_fsink_input. */ upipe_release(upipe); if (unlikely(path == NULL)) return UBASE_ERR_NONE; upipe_fsink_check_upump_mgr(upipe); const char *mode_desc = NULL; /* hush gcc */ int flags; switch (mode) { case UPIPE_FSINK_NONE: flags = 0; break; case UPIPE_FSINK_APPEND: mode_desc = "append"; flags = O_CREAT; break; case UPIPE_FSINK_OVERWRITE: mode_desc = "overwrite"; flags = O_CREAT | O_TRUNC; break; case UPIPE_FSINK_CREATE: mode_desc = "create"; flags = O_CREAT | O_EXCL; break; default: upipe_err_va(upipe, "invalid mode %d", mode); return UBASE_ERR_INVALID; } upipe_fsink->fd = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC | flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (unlikely(upipe_fsink->fd == -1)) { upipe_err_va(upipe, "can't open file %s (%s)", path, mode_desc); return UBASE_ERR_EXTERNAL; } switch (mode) { /* O_APPEND seeks on each write, so use this instead */ case UPIPE_FSINK_APPEND: if (unlikely(lseek(upipe_fsink->fd, 0, SEEK_END) == -1)) { upipe_err_va(upipe, "can't append to file %s (%s)", path, mode_desc); close(upipe_fsink->fd); upipe_fsink->fd = -1; return UBASE_ERR_EXTERNAL; } break; default: break; } upipe_fsink->path = strdup(path); if (unlikely(upipe_fsink->path == NULL)) { close(upipe_fsink->fd); upipe_fsink->fd = -1; upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } if (!upipe_fsink_check_input(upipe)) /* Use again the pipe that we previously released. */ upipe_use(upipe); upipe_notice_va(upipe, "opening file %s in %s mode", upipe_fsink->path, mode_desc); return UBASE_ERR_NONE; }
/** @internal @This allocates a wsink pipe. * * @param mgr common management structure * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to upipe or NULL in case of allocation error */ static struct upipe *_upipe_wsink_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct upipe_wsink_mgr *wsink_mgr = upipe_wsink_mgr_from_upipe_mgr(mgr); if (unlikely(signature != UPIPE_WSINK_SIGNATURE || wsink_mgr->xfer_mgr == NULL)) goto upipe_wsink_alloc_err; struct upipe *remote = va_arg(args, struct upipe *); struct uprobe *uprobe_remote = va_arg(args, struct uprobe *); unsigned int queue_length = va_arg(args, unsigned int); assert(queue_length); if (unlikely(remote == NULL)) goto upipe_wsink_alloc_err2; struct upipe_wsink *upipe_wsink = malloc(sizeof(struct upipe_wsink)); if (unlikely(upipe_wsink == NULL)) goto upipe_wsink_alloc_err2; struct upipe *upipe = upipe_wsink_to_upipe(upipe_wsink); upipe_init(upipe, mgr, uprobe); upipe_wsink_init_urefcount(upipe); urefcount_init(upipe_wsink_to_urefcount_real(upipe_wsink), upipe_wsink_free); upipe_wsink_init_bin_input(upipe); uprobe_init(&upipe_wsink->proxy_probe, upipe_wsink_proxy_probe, NULL); upipe_wsink->proxy_probe.refcount = upipe_wsink_to_urefcount_real(upipe_wsink); uprobe_init(&upipe_wsink->in_qsrc_probe, upipe_wsink_in_qsrc_probe, uprobe_remote); upipe_wsink->in_qsrc_probe.refcount = upipe_wsink_to_urefcount_real(upipe_wsink); upipe_throw_ready(upipe); /* remote */ upipe_use(remote); struct upipe *remote_xfer = upipe_xfer_alloc(wsink_mgr->xfer_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_wsink->proxy_probe), UPROBE_LOG_VERBOSE, "sink_xfer"), remote); if (unlikely(remote_xfer == NULL)) { upipe_release(remote); upipe_release(upipe); return NULL; } upipe_attach_upump_mgr(remote_xfer); /* input queue */ struct upipe *in_qsrc = upipe_qsrc_alloc(wsink_mgr->qsrc_mgr, uprobe_pfx_alloc( uprobe_use(&upipe_wsink->in_qsrc_probe), UPROBE_LOG_VERBOSE, "in_qsrc"), queue_length > UINT8_MAX ? UINT8_MAX : queue_length); if (unlikely(in_qsrc == NULL)) goto upipe_wsink_alloc_err3; struct upipe *in_qsink = upipe_qsink_alloc(wsink_mgr->qsink_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_wsink->proxy_probe), UPROBE_LOG_VERBOSE, "in_qsink"), in_qsrc); if (unlikely(in_qsink == NULL)) goto upipe_wsink_alloc_err3; upipe_wsink_store_bin_input(upipe, in_qsink); if (queue_length > UINT8_MAX) upipe_set_max_length(upipe_wsink->in_qsink, queue_length - UINT8_MAX); struct upipe *in_qsrc_xfer = upipe_xfer_alloc(wsink_mgr->xfer_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_wsink->proxy_probe), UPROBE_LOG_VERBOSE, "in_qsrc_xfer"), in_qsrc); if (unlikely(in_qsrc_xfer == NULL)) goto upipe_wsink_alloc_err3; upipe_set_output(in_qsrc_xfer, remote); upipe_attach_upump_mgr(in_qsrc_xfer); upipe_release(remote); upipe_release(remote_xfer); upipe_release(in_qsrc_xfer); return upipe; upipe_wsink_alloc_err3: upipe_release(remote); upipe_release(remote_xfer); upipe_release(upipe); return NULL; upipe_wsink_alloc_err2: upipe_release(remote); upipe_wsink_alloc_err: uprobe_release(uprobe); return NULL; }
/** @internal @This handles data. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer * @return false if the input must be blocked */ static bool upipe_speexdsp_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); struct urational drift_rate; if (!ubase_check(uref_clock_get_rate(uref, &drift_rate))) drift_rate = (struct urational){ 1, 1 }; /* reinitialize resampler when drift rate changes */ if (urational_cmp(&drift_rate, &upipe_speexdsp->drift_rate)) { upipe_speexdsp->drift_rate = drift_rate; spx_uint32_t ratio_num = drift_rate.den; spx_uint32_t ratio_den = drift_rate.num; spx_uint32_t in_rate = upipe_speexdsp->rate * ratio_num / ratio_den; spx_uint32_t out_rate = upipe_speexdsp->rate; int err = speex_resampler_set_rate_frac(upipe_speexdsp->ctx, ratio_num, ratio_den, in_rate, out_rate); if (err) { upipe_err_va(upipe, "Couldn't resample from %u to %u: %s", in_rate, out_rate, speex_resampler_strerror(err)); } else { upipe_dbg_va(upipe, "Resampling from %u to %u", in_rate, out_rate); } } size_t size; if (!ubase_check(uref_sound_size(uref, &size, NULL /* sample_size */))) { uref_free(uref); return true; } struct ubuf *ubuf = ubuf_sound_alloc(upipe_speexdsp->ubuf_mgr, size + 10); if (!ubuf) return false; const void *in; uref_sound_read_void(uref, 0, -1, &in, 1); void *out; ubuf_sound_write_void(ubuf, 0, -1, &out, 1); spx_uint32_t in_len = size; /* input size */ spx_uint32_t out_len = size + 10; /* available output size */ int err; if (upipe_speexdsp->f32) err = speex_resampler_process_interleaved_float(upipe_speexdsp->ctx, in, &in_len, out, &out_len); else err = speex_resampler_process_interleaved_int(upipe_speexdsp->ctx, in, &in_len, out, &out_len); if (err) { upipe_err_va(upipe, "Could not resample: %s", speex_resampler_strerror(err)); } uref_sound_unmap(uref, 0, -1, 1); ubuf_sound_unmap(ubuf, 0, -1, 1); if (err) { ubuf_free(ubuf); } else { ubuf_sound_resize(ubuf, 0, out_len); uref_attach_ubuf(uref, ubuf); } upipe_speexdsp_output(upipe, uref, upump_p); return true; } /** @internal @This receives incoming uref. * * @param upipe description structure of the pipe * @param uref uref structure describing the picture * @param upump_p reference to pump that generated the buffer */ static void upipe_speexdsp_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { if (!upipe_speexdsp_check_input(upipe)) { upipe_speexdsp_hold_input(upipe, uref); upipe_speexdsp_block_input(upipe, upump_p); } else if (!upipe_speexdsp_handle(upipe, uref, upump_p)) { upipe_speexdsp_hold_input(upipe, uref); upipe_speexdsp_block_input(upipe, upump_p); /* Increment upipe refcount to avoid disappearing before all packets * have been sent. */ upipe_use(upipe); } } /** @internal @This receives a provided ubuf manager. * * @param upipe description structure of the pipe * @param flow_format amended flow format * @return an error code */ static int upipe_speexdsp_check(struct upipe *upipe, struct uref *flow_format) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); if (flow_format != NULL) upipe_speexdsp_store_flow_def(upipe, flow_format); if (upipe_speexdsp->flow_def == NULL) return UBASE_ERR_NONE; bool was_buffered = !upipe_speexdsp_check_input(upipe); upipe_speexdsp_output_input(upipe); upipe_speexdsp_unblock_input(upipe); if (was_buffered && upipe_speexdsp_check_input(upipe)) { /* All packets have been output, release again the pipe that has been * used in @ref upipe_speexdsp_input. */ upipe_release(upipe); } return UBASE_ERR_NONE; } /** @internal @This sets the input flow definition. * * @param upipe description structure of the pipe * @param flow_def flow definition packet * @return an error code */ static int upipe_speexdsp_set_flow_def(struct upipe *upipe, struct uref *flow_def) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); if (flow_def == NULL) return UBASE_ERR_INVALID; const char *def; UBASE_RETURN(uref_flow_get_def(flow_def, &def)) if (unlikely(ubase_ncmp(def, "sound.f32.") && ubase_ncmp(def, "sound.s16."))) return UBASE_ERR_INVALID; uint8_t in_planes; if (unlikely(!ubase_check(uref_sound_flow_get_planes(flow_def, &in_planes)))) return UBASE_ERR_INVALID; if (in_planes != 1) { upipe_err(upipe, "only interleaved audio is supported"); return UBASE_ERR_INVALID; } if (!ubase_check(uref_sound_flow_get_rate(flow_def, &upipe_speexdsp->rate))) { upipe_err(upipe, "no sound rate defined"); uref_dump(flow_def, upipe->uprobe); return UBASE_ERR_INVALID; } uint8_t channels; if (unlikely(!ubase_check(uref_sound_flow_get_channels(flow_def, &channels)))) return UBASE_ERR_INVALID; flow_def = uref_dup(flow_def); if (unlikely(flow_def == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } upipe_speexdsp_require_ubuf_mgr(upipe, flow_def); if (upipe_speexdsp->ctx) speex_resampler_destroy(upipe_speexdsp->ctx); upipe_speexdsp->f32 = !ubase_ncmp(def, "sound.f32."); int err; upipe_speexdsp->ctx = speex_resampler_init(channels, upipe_speexdsp->rate, upipe_speexdsp->rate, upipe_speexdsp->quality, &err); if (!upipe_speexdsp->ctx) { upipe_err_va(upipe, "Could not create resampler: %s", speex_resampler_strerror(err)); return UBASE_ERR_INVALID; } return UBASE_ERR_NONE; } /** @internal @This provides a flow format suggestion. * * @param upipe description structure of the pipe * @param request description structure of the request * @return an error code */ static int upipe_speexdsp_provide_flow_format(struct upipe *upipe, struct urequest *request) { const char *def; UBASE_RETURN(uref_flow_get_def(request->uref, &def)) uint8_t channels; UBASE_RETURN(uref_sound_flow_get_channels(request->uref, &channels)) uint8_t planes; UBASE_RETURN(uref_sound_flow_get_planes(request->uref, &planes)) uint8_t sample_size; UBASE_RETURN(uref_sound_flow_get_sample_size(request->uref, &sample_size)) struct uref *flow = uref_dup(request->uref); UBASE_ALLOC_RETURN(flow); uref_sound_flow_clear_format(flow); uref_sound_flow_set_planes(flow, 0); uref_sound_flow_set_channels(flow, channels); uref_sound_flow_add_plane(flow, "all"); if (ubase_ncmp(def, "sound.s16.")) { uref_flow_set_def(flow, "sound.f32."); /* prefer f32 over s16 */ uref_sound_flow_set_sample_size(flow, 4 * channels); } else { uref_flow_set_def(flow, def); uref_sound_flow_set_sample_size(flow, (planes > 1) ? sample_size : sample_size / channels); } return urequest_provide_flow_format(request, flow); } /** @internal @This processes control commands on a speexdsp pipe. * * @param upipe description structure of the pipe * @param command type of command to process * @param args arguments of the command * @return an error code */ static int upipe_speexdsp_control(struct upipe *upipe, int command, va_list args) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); switch (command) { /* generic commands */ case UPIPE_REGISTER_REQUEST: { struct urequest *request = va_arg(args, struct urequest *); if (request->type == UREQUEST_FLOW_FORMAT) return upipe_speexdsp_provide_flow_format(upipe, request); if (request->type == UREQUEST_UBUF_MGR) return upipe_throw_provide_request(upipe, request); return upipe_speexdsp_alloc_output_proxy(upipe, request); } case UPIPE_UNREGISTER_REQUEST: { struct urequest *request = va_arg(args, struct urequest *); if (request->type == UREQUEST_FLOW_FORMAT || request->type == UREQUEST_UBUF_MGR) return UBASE_ERR_NONE; return upipe_speexdsp_free_output_proxy(upipe, request); } case UPIPE_GET_OUTPUT: { struct upipe **p = va_arg(args, struct upipe **); return upipe_speexdsp_get_output(upipe, p); } case UPIPE_SET_OUTPUT: { struct upipe *output = va_arg(args, struct upipe *); return upipe_speexdsp_set_output(upipe, output); } case UPIPE_GET_FLOW_DEF: { struct uref **p = va_arg(args, struct uref **); return upipe_speexdsp_get_flow_def(upipe, p); } case UPIPE_SET_FLOW_DEF: { struct uref *flow = va_arg(args, struct uref *); return upipe_speexdsp_set_flow_def(upipe, flow); } case UPIPE_SET_OPTION: { const char *option = va_arg(args, const char *); const char *value = va_arg(args, const char *); if (strcmp(option, "quality")) return UBASE_ERR_INVALID; if (upipe_speexdsp->ctx) return UBASE_ERR_BUSY; int quality = atoi(value); if (quality > SPEEX_RESAMPLER_QUALITY_MAX) { quality = SPEEX_RESAMPLER_QUALITY_MAX; upipe_err_va(upipe, "Clamping quality to %d", SPEEX_RESAMPLER_QUALITY_MAX); } else if (quality < SPEEX_RESAMPLER_QUALITY_MIN) { quality = SPEEX_RESAMPLER_QUALITY_MIN; upipe_err_va(upipe, "Clamping quality to %d", SPEEX_RESAMPLER_QUALITY_MIN); } upipe_speexdsp->quality = quality; return UBASE_ERR_NONE; } default: return UBASE_ERR_UNHANDLED; } } /** @internal @This allocates a speexdsp pipe. * * @param mgr common management structure * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to upipe or NULL in case of allocation error */ static struct upipe *upipe_speexdsp_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct upipe *upipe = upipe_speexdsp_alloc_void(mgr, uprobe, signature, args); if (unlikely(upipe == NULL)) return NULL; struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); upipe_speexdsp->ctx = NULL; upipe_speexdsp->drift_rate = (struct urational){ 0, 0 }; upipe_speexdsp->quality = SPEEX_RESAMPLER_QUALITY_MAX; upipe_speexdsp_init_urefcount(upipe); upipe_speexdsp_init_ubuf_mgr(upipe); upipe_speexdsp_init_output(upipe); upipe_speexdsp_init_flow_def(upipe); upipe_speexdsp_init_input(upipe); upipe_throw_ready(upipe); return upipe; } /** @This frees a upipe. * * @param upipe description structure of the pipe */ static void upipe_speexdsp_free(struct upipe *upipe) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); if (likely(upipe_speexdsp->ctx)) speex_resampler_destroy(upipe_speexdsp->ctx); upipe_throw_dead(upipe); upipe_speexdsp_clean_input(upipe); upipe_speexdsp_clean_output(upipe); upipe_speexdsp_clean_flow_def(upipe); upipe_speexdsp_clean_ubuf_mgr(upipe); upipe_speexdsp_clean_urefcount(upipe); upipe_speexdsp_free_void(upipe); } /** module manager static descriptor */ static struct upipe_mgr upipe_speexdsp_mgr = { .refcount = NULL, .signature = UPIPE_SPEEXDSP_SIGNATURE, .upipe_alloc = upipe_speexdsp_alloc, .upipe_input = upipe_speexdsp_input, .upipe_control = upipe_speexdsp_control, .upipe_mgr_control = NULL }; /** @This returns the management structure for speexdsp pipes * * @return pointer to manager */ struct upipe_mgr *upipe_speexdsp_mgr_alloc(void) { return &upipe_speexdsp_mgr; }
/** @internal @This catches events of the video output of the demux. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_demux_output(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_demux_output_s); switch (event) { case UPROBE_NEED_OUTPUT: { struct uref *flow_def = va_arg(args, struct uref *); const char *def = "(none)"; if (!ubase_check(uref_flow_get_def(flow_def, &def)) || ubase_ncmp(def, "block.")) { upipe_warn_va(upipe, "flow def %s is not supported", def); return UBASE_ERR_UNHANDLED; } upipe_dbg_va(upipe, "add flow %s", def); /* prepare a queue to deport avcodec to a new thread */ uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_FREEZE_UPUMP_MGR); struct upipe *upipe_dec_qsrc = upipe_qsrc_alloc(glxplayer->upipe_qsrc_mgr, uprobe_pfx_alloc_va(uprobe_use(&glxplayer->uprobe_dec_qsrc_s), glxplayer->loglevel, "dec qsrc"), DEC_QUEUE_LENGTH); if (unlikely(upipe_dec_qsrc == NULL)) { return UBASE_ERR_ALLOC; } uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_THAW_UPUMP_MGR); glxplayer->upipe_dec_qsink = upipe_qsink_alloc(glxplayer->upipe_qsink_mgr, uprobe_pfx_alloc_va( uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "dec qsink"), upipe_dec_qsrc); if (unlikely(glxplayer->upipe_dec_qsink == NULL)) { upipe_release(upipe_dec_qsrc); return UBASE_ERR_ALLOC; } upipe_set_output(upipe, glxplayer->upipe_dec_qsink); /* prepare to transfer the queue source */ glxplayer->dec_xfer = upipe_xfer_mgr_alloc(XFER_QUEUE, XFER_POOL); if (unlikely(glxplayer->dec_xfer == NULL)) { upipe_release(upipe_dec_qsrc); return UBASE_ERR_ALLOC; } /* spawn a thread for the decoder */ if (pthread_create(&glxplayer->dec_thread_id, NULL, upipe_glxplayer_dec_thread, glxplayer)) { upipe_mgr_release(glxplayer->dec_xfer); upipe_release(upipe_dec_qsrc); return UBASE_ERR_ALLOC; } glxplayer->upipe_dec_qsrc_handle = upipe_xfer_alloc(glxplayer->dec_xfer, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "dec qsrc xfer"), upipe_dec_qsrc); if (unlikely(glxplayer->upipe_dec_qsrc_handle == NULL)) { upipe_mgr_release(glxplayer->dec_xfer); upipe_release(upipe_dec_qsrc); return UBASE_ERR_ALLOC; } upipe_attach_upump_mgr(glxplayer->upipe_dec_qsrc_handle); upipe_set_output(glxplayer->upipe_dec_qsink, glxplayer->upipe_dec_qsrc_handle); return UBASE_ERR_NONE; } case UPROBE_SOURCE_END: { upipe_flush(glxplayer->upipe_dec_qsink); upipe_release(glxplayer->upipe_dec_qsink); glxplayer->upipe_dec_qsink = NULL; /* set dec_qsrc output to null */ struct upipe *null = upipe_void_alloc(glxplayer->upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "dec qsrc null")); if (likely(null != NULL)) { upipe_set_output(glxplayer->upipe_dec_qsrc_handle, null); upipe_release(null); } upipe_release(glxplayer->upipe_dec_qsrc_handle); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }