예제 #1
0
/** @internal @This is the open_codec upump callback
 * It calls _open_codec_cb.
 *
 * @param upump description structure of the pump
 */
static void upipe_avcdec_open_codec_cb(struct upump *upump)
{
    assert(upump);
    struct upipe *upipe = upump_get_opaque(upump, struct upipe*);
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    struct upipe_avcodec_open_params *params = &upipe_avcdec->open_params;
    struct upump *upump_av_deal = upipe_avcdec->upump_av_deal;

    /* check udeal */
    if (upump_av_deal) {
        if (unlikely(!upipe_av_deal_grab())) {
            upipe_dbg(upipe, "could not grab resource, return");
            return;
        }
        upipe_avcdec->upump_av_deal = NULL;
    }

    /* real open_codec function */
    bool ret = upipe_avcdec_open_codec(upipe, params->codec,
                  params->extradata, params->extradata_size);

    /* clean dealer */
    if (unlikely(!upipe_av_deal_yield(upump_av_deal))) {
        upump_free(upump_av_deal);
        upump_av_deal = NULL;
        upipe_err(upipe, "can't stop dealer");
        upipe_throw_upump_error(upipe);
        if (upipe_avcdec->context) {
            avcodec_close(upipe_avcdec->context);
            av_free(upipe_avcdec->context);
            upipe_avcdec->context = NULL;
        }
        return;
    }
    upump_free(upump_av_deal);
    upump_av_deal = NULL;

    if (!ret) {
        return;
    }

    /* unblock input pump*/
    if (upipe_avcdec->saved_upump_mgr) {
        upipe_dbg(upipe, "unblocking saved upump_mgr");
        upump_mgr_sink_unblock(upipe_avcdec->saved_upump_mgr);
        upump_mgr_release(upipe_avcdec->saved_upump_mgr);
        upipe_avcdec->saved_upump_mgr = NULL;
    }
}
예제 #2
0
/** @internal @This handles input buffer of the blank source pipe. This buffer
 * is supposed to be a picture or a sound to set as source buffer of the blank
 * pipes (audio/video blank pipe generator).
 *
 * @param upipe description structure of the pipe
 * @param uref uref reference picture or sound
 * @param upump_p is ignored
 */
static void upipe_blksrc_input(struct upipe *upipe,
                               struct uref *uref,
                               struct upump **upump_p)
{
    struct upipe_blksrc *upipe_blksrc = upipe_blksrc_from_upipe(upipe);
    if (unlikely(!upipe_blksrc->flow_def)) {
        upipe_warn(upipe, "flow def is not set");
        uref_free(uref);
    }
    else if (ubase_check(uref_flow_match_def(upipe_blksrc->flow_def,
                                             UREF_PIC_FLOW_DEF))) {
        upipe_dbg(upipe, "set picture buffer");
        upipe_vblk_set_pic(upipe_blksrc->blk, uref);
    }
    else if (ubase_check(uref_flow_match_def(upipe_blksrc->flow_def,
                                             UREF_SOUND_FLOW_DEF)))
        upipe_ablk_set_sound(upipe_blksrc->blk, uref);
    else {
        upipe_warn(upipe, "unsupported flow definition");
        uref_free(uref);
    }
}
예제 #3
0
/** @internal @This handles packets.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump upump structure
 */
static void upipe_avcdec_input_packet(struct upipe *upipe, struct uref *uref,
                              struct upump *upump)
{
    uint8_t *inbuf;
    size_t insize = 0;

    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    assert(upipe);
    assert(uref);

    if (upipe_avcdec->upump_av_deal) { /* pending open_codec callback */
        upipe_dbg(upipe, "Received packet while open_codec pending");
        if (upump) {
            upump_mgr_sink_block(upump->mgr);
            upump_mgr_use(upump->mgr);
            upipe_avcdec->saved_upump_mgr = upump->mgr;
        }
        if (upipe_avcdec->saved_uref) {
            upipe_warn(upipe, "Dropping previously saved packet !");
            uref_free(upipe_avcdec->saved_uref);
        }
        upipe_avcdec->saved_uref = uref;
        return;
    } else if (upipe_avcdec->saved_uref) {
        upipe_dbg(upipe, "Processing previously saved packet");
        struct uref *prev_uref = upipe_avcdec->saved_uref;
        upipe_avcdec->saved_uref = NULL;
        /* Not a typo, using the current upump here */
        upipe_avcdec_input_packet(upipe, prev_uref, upump); 
    }

    if (!upipe_avcdec->context) {
        uref_free(uref);
        upipe_warn(upipe, "Received packet but decoder is not initialized");
        return;
    }

    /* avcodec input buffer needs to be at least 4-byte aligned and
       FF_INPUT_BUFFER_PADDING_SIZE larger than actual input size.
       Thus, extract ubuf content in a properly allocated buffer.
       Padding must be zeroed. */
    uref_block_size(uref, &insize);
    if (unlikely(!insize)) {
        upipe_warn(upipe, "Received packet with size 0, dropping");
        uref_free(uref);
        return;
    }

    upipe_dbg_va(upipe, "Received packet %u - size : %u", upipe_avcdec->counter, insize);
    inbuf = malloc(insize + FF_INPUT_BUFFER_PADDING_SIZE);
    if (unlikely(!inbuf)) {
        upipe_throw_aerror(upipe);
        return;
    }
    memset(inbuf, 0, insize + FF_INPUT_BUFFER_PADDING_SIZE);
    uref_block_extract(uref, 0, insize, inbuf); 
    ubuf_free(uref_detach_ubuf(uref));

    uref_pic_set_number(uref, upipe_avcdec->counter);

    /* Track current uref in pipe structure - required for buffer allocation
     * in upipe_avcdec_get_buffer */
    upipe_avcdec->uref = uref;

    upipe_avcdec_process_buf(upipe, inbuf, insize, upump);

    free(inbuf);
    uref_free(uref);
    upipe_avcdec->counter++;
}
예제 #4
0
/** @internal @This configures a new codec context
 *
 * @param upipe description structure of the pipe
 * @param codec_def codec defintion string
 * @param extradata pointer to extradata buffer
 * @param extradata_size extradata size
 * @return false if the buffer couldn't be accepted
 */
static bool _upipe_avcdec_set_codec(struct upipe *upipe, const char *codec_def,
                                     uint8_t *extradata, int extradata_size)
{
    AVCodec *codec = NULL;
    int codec_id = 0;
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    struct upipe_avcodec_open_params *params = &upipe_avcdec->open_params;
    uint8_t *extradata_padded = NULL;
 
    /* find codec */
    if (codec_def) {
        codec_id = upipe_av_from_flow_def(codec_def);
        if (unlikely(!codec_id)) {
            upipe_warn_va(upipe, "codec %s not found", codec_def);
        }
        codec = avcodec_find_decoder(codec_id);
        if (unlikely(!codec)) {
            upipe_warn_va(upipe, "codec %s (%d) not found", codec_def, codec_id);
        }
    }

    /* copy extradata if present */
    if (extradata && extradata_size > 0) {
        extradata_padded = upipe_avcdec_copy_extradata(upipe,
                                    extradata, extradata_size);
        if (unlikely(!extradata_padded)) {
            extradata_size = 0;
        }
    }

    /* use udeal/upump callback if available */
    if (upipe_avcdec->upump_mgr) {
        upipe_dbg(upipe, "upump_mgr present, using udeal");

        if (unlikely(upipe_avcdec->upump_av_deal)) {
            upipe_dbg(upipe, "previous upump_av_deal still running, cleaning first");
            upipe_avcdec_abort_av_deal(upipe);
        } else {
            upipe_use(upipe);
        }

        struct upump *upump_av_deal = upipe_av_deal_upump_alloc(upipe_avcdec->upump_mgr,
                                                     upipe_avcdec_open_codec_cb, upipe);
        if (unlikely(!upump_av_deal)) {
            upipe_err(upipe, "can't create dealer");
            upipe_throw_upump_error(upipe);
            return false;
        }
        upipe_avcdec->upump_av_deal = upump_av_deal;

        memset(params, 0, sizeof(struct upipe_avcodec_open_params));
        params->codec = codec;
        params->extradata = extradata_padded;
        params->extradata_size = extradata_size;

        /* fire */
        upipe_av_deal_start(upump_av_deal);
        return true;

    } else {
        upipe_dbg(upipe, "no upump_mgr present, direct call to avcdec_open");
        upipe_use(upipe);
        return upipe_avcdec_open_codec(upipe, codec, extradata_padded, extradata_size);
    }
}
예제 #5
0
/** @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;
}
예제 #6
0
/** @internal @This asks to open the given device.
 *
 * @param upipe description structure of the pipe
 * @param path relative or absolute path of the file
 * @return an error code
 */
static int upipe_dveo_asi_sink_open(struct upipe *upipe)
{
#define BYPASS_MODE 1

    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);
    char path[20], sys[50], buf[20];
    memset(buf, 0, sizeof(buf));

    static const char dev_fmt[] = "/dev/asitx%u";
    static const char sys_fmt[] = "/sys/class/asi/asitx%u/%s";
    static const char dvbm_sys_fmt[] = "/sys/class/dvbm/%u/%s";

    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "timestamps");
    snprintf(buf, sizeof(buf), "%u\n", 2);
    if (util_write(sys, buf, sizeof(buf)) < 0) {
        upipe_err_va(upipe, "Couldn't set timestamp mode (%m)");
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "bufsize");
    snprintf(buf, sizeof(buf), "%u\n", 6*(188+8)); /* minimum is 1024 */
    if (util_write(sys, buf, sizeof(buf)) < 0) {
        upipe_err_va(upipe, "Couldn't set buffer size (%m)");
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "buffers");
    snprintf(buf, sizeof(buf), "%u\n", 500);
    if (util_write(sys, buf, sizeof(buf)) < 0) {
        upipe_err_va(upipe, "Couldn't set # of buffers (%m)");
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(path, sizeof(path), dev_fmt, upipe_dveo_asi_sink->card_idx);
    int fd = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
    if (unlikely(fd < 0)) {
        upipe_err_va(upipe, "can't open file %s (%m)", path);
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(sys, sizeof(sys), dvbm_sys_fmt, upipe_dveo_asi_sink->card_idx, "bypass_mode");
    snprintf(buf, sizeof(buf), "%u", BYPASS_MODE);
    util_write(sys, buf, sizeof(buf)); /* Not all cards have this so don't fail */

    unsigned int cap;
    if (ioctl(fd, ASI_IOC_TXGETCAP, &cap) < 0) {
        upipe_err_va(upipe, "can't get tx caps (%m)");
        goto error;
    }

    unsigned long int bufsize;
    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "bufsize");
    if (util_strtoul(sys, &bufsize) < 0) {
        upipe_err(upipe, "Couldn't read buffer size");
        goto error;
    }

    unsigned long int mode;
    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "mode");
    if (util_strtoul(sys, &mode) < 0) {
        upipe_err(upipe, "Couldn't read buffer size");
        goto error;
    }

    switch (mode) {
        case ASI_CTL_TX_MODE_MAKE204:
            upipe_dbg(upipe, "Appending 0x00 bytes to make 204 bytes packets");
        case ASI_CTL_TX_MODE_188:
        case ASI_CTL_TX_MODE_204:
            break;
        default:
            upipe_err_va(upipe, "Unknown TX mode %lu", mode);
            goto error;
    }

    unsigned long int clock_source = 0;
    if (cap & ASI_CAP_TX_SETCLKSRC) {
        snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "clock_source");
        if (util_strtoul(sys, &clock_source) < 0) {
            upipe_err(upipe, "Couldn't read clock source");
            goto error;
        }
    }

    switch (clock_source) {
        case ASI_CTL_TX_CLKSRC_ONBOARD:
            upipe_dbg(upipe, "Using onboard oscillator");
            break;
        case ASI_CTL_TX_CLKSRC_EXT:
            upipe_dbg(upipe, "Using external reference clock");
            break;
        case ASI_CTL_TX_CLKSRC_RX:
            upipe_dbg(upipe, "Using recovered receive clock");
            break;
        default:
            upipe_dbg(upipe, "Unknown clock source");
                break;
    }

    if (!(cap & ASI_CAP_TX_TIMESTAMPS)) {
        upipe_err(upipe, "Device does not support timestamps");
        goto error;
    }

    upipe_dveo_asi_sink->fd = fd;

    upipe_notice_va(upipe, "opening file %s", path);
    return UBASE_ERR_NONE;

error:
    close(fd);
    return UBASE_ERR_EXTERNAL;
}