Exemple #1
0
static pj_status_t pj_vpx_codec_decode(pjmedia_vid_codec *codec,
                                       pj_size_t pkt_count,
                                       pjmedia_frame packets[],
                                       unsigned out_size,
                                       pjmedia_frame *output) {
    vpx_private *vpx = (vpx_private*) codec->codec_data;
    vpx_image_t *img;
    vpx_codec_iter_t iter;
    int i, res;

    PJ_ASSERT_RETURN(codec && pkt_count > 0 && packets && output, PJ_EINVAL);

    vpx->dec_frame_len = 0;

    /* TODO : packet parsing is absolutely incomplete here !!!!
     * We should manage extensions, partitions etc
     * */
    for (i = 0; i < pkt_count; ++i) {
        pj_uint8_t *data;
        pj_uint8_t extended_bit, s_bit, partition_id;
        unsigned extension_len = 0;
        unsigned payload_size = packets[i].size;

        if(payload_size == 0) {
            continue;
        }

        data = packets[i].buf;
        extended_bit = (*data) & 0x80;
        s_bit = (*data) & 0x20;
        partition_id = (*data) & 0x1F;

        PJ_UNUSED_ARG(s_bit);
        PJ_UNUSED_ARG(partition_id);

        /* First octet is for */
        /* |X|R|N|S|PartID | */
        if(extended_bit) {
            pj_uint8_t i_bit, l_bit, t_bit, k_bit;
            (data)++;
            extension_len++;
            i_bit = (*data) & 0x80;
            l_bit = (*data) & 0x40;
            t_bit = (*data) & 0x20;
            k_bit = (*data) & 0x10;
            if(payload_size <= 1) {
                PJ_LOG(4, (THIS_FILE, "Error decoding VP8 extended attributes"));
                continue;
            }
            /* We have extension in octet 2 */
            /* |I|L|T|K| RSV   | */
            if (i_bit) {
                data++;
                if(payload_size <= 2){
                    PJ_LOG(4, (THIS_FILE, "Error decoding VP8 extended picture ID attribute"));
                    continue;
                }
                // I present check M flag for long picture ID
                if ((*data) & 0x80) {
                    data++;
                }
            }
            if (l_bit) {
                data++;
            }
            if (t_bit || k_bit) {
                data++;
            }
        }

        data++;
        payload_size = packets[i].size - (data - (pj_uint8_t*)packets[i].buf);

        //PJ_LOG(4, (THIS_FILE, "Unpack RTP %d size %d, start %d", i, packets[i].size, s[0] & 0x10));
        if((vpx->dec_frame_len + payload_size) < vpx->dec_buf_size) {
            pj_memcpy(vpx->dec_buf + vpx->dec_frame_len, data, payload_size);
            vpx->dec_frame_len += payload_size;
        } else {
            PJ_LOG(1, (THIS_FILE, "Buffer is too small"));
        }
    }

    if(vpx->dec_frame_len == 0){
        PJ_LOG(1, (THIS_FILE, "No content for these packets"));
        return PJ_SUCCESS;
    }

    res = vpx_codec_decode(&vpx->decoder, vpx->dec_buf, vpx->dec_frame_len, NULL, VPX_DL_REALTIME);
    switch (res) {
        case VPX_CODEC_UNSUP_BITSTREAM:
        case VPX_CODEC_UNSUP_FEATURE:
        case VPX_CODEC_CORRUPT_FRAME:
            /* Fatal errors to the stream, request a keyframe to see if we can recover */
            PJ_LOG(4, (THIS_FILE, "Fatal error decoding stream: (%d) %s", res, vpx_codec_err_to_string(res)));
            pjmedia_event event;
            pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING, NULL, codec);
            pjmedia_event_publish(NULL, codec, &event, 0);
            return PJMEDIA_CODEC_EBADBITSTREAM;
        case VPX_CODEC_OK:
            break;
        default:
            PJ_LOG(4, (THIS_FILE, "Failed to decode packets: (%d) %s", res, vpx_codec_err_to_string(res)));
            return PJMEDIA_ERROR;
    }

    iter = NULL;
    for (;;) {
        pj_status_t status;
        img = vpx_codec_get_frame(&vpx->decoder, &iter);
        if (img == NULL)
            break;
        status = pj_vpx_codec_decode_whole(codec, img, &packets[0].timestamp, out_size, output);
        if (status != PJ_SUCCESS) {
            PJ_LOG(4, (THIS_FILE, "Failed to decode frame"));
            /* XXX stop processing and request keyframe? */
        }
    }

    return PJ_SUCCESS;
}
Exemple #2
0
static pj_status_t pj_vpx_codec_decode(pjmedia_vid_codec *codec,
        pj_size_t pkt_count, pjmedia_frame packets[], unsigned out_size,
        pjmedia_frame *output) {
    vpx_private *vpx = (vpx_private*) codec->codec_data;
    pj_status_t status;
    pj_uint8_t *p;
    pj_uint8_t *s;
    vpx_image_t *img;
    vpx_codec_iter_t iter = NULL;
    int i, res;

    PJ_ASSERT_RETURN(codec && pkt_count > 0 && packets && output, PJ_EINVAL);

    i = 0;

    output->type = PJMEDIA_FRAME_TYPE_NONE;
    output->size = 0;

    s = packets[0].buf;
    p = vpx->dec_buf;
    vpx->dec_frame_len = 0;

    /* TODO : packet parsing is absolutely incomplete here !!!!
     * We should manage extensions, partitions etc
     * */
    for (i = 0; i < pkt_count; ++i) {
        unsigned extension_len = 0;
        unsigned payload_size = packets[i].size;

        if(payload_size <= 0){
            continue;
        }

        s = packets[i].buf;

        /* First octet is for */
        /* |X|R|N|S|PartID | */
        if( s[0] & 0x80 ){
            if(payload_size <= 1){
                continue;
            }
            /* We have extension in octet 2 */
            /* |I|L|T|K| RSV   | */
            if( s[1] & 0x80 ){
                extension_len++;
                if(payload_size <= 2){
                    continue;
                }
                // I present check M flag for long picture ID
                if( s[2] & 0x80 ) extension_len++;
            }
            if( s[1] & 0x40 ) extension_len++;
            if( (s[1] & 0x20) | (s[1] & 0x10) ) extension_len++;
        }

        s += (extension_len + 1);
        payload_size -= (extension_len + 1);


        //PJ_LOG(4, (THIS_FILE, "Unpack RTP %d size %d, start %d", i, packets[i].size, s[0] & 0x10));
        if((vpx->dec_frame_len + payload_size) < vpx->dec_buf_size) {
            pj_memcpy((p + vpx->dec_frame_len), s, payload_size);
            vpx->dec_frame_len += payload_size;
        } else {
            PJ_LOG(1, (THIS_FILE, "Buffer is too small"));
        }
    }

    if(vpx->dec_frame_len == 0){
        PJ_LOG(1, (THIS_FILE, "No content for these packets"));
        return PJ_SUCCESS;
    }

    res = vpx_codec_decode(&vpx->decoder,
            vpx->dec_buf, vpx->dec_frame_len,
            0, VPX_DL_REALTIME);
    if (res == VPX_CODEC_UNSUP_BITSTREAM){
        PJ_LOG(2, (THIS_FILE, "More likely we are missing a keyframe, request it"));
        /* Broadcast missing keyframe event */
       pjmedia_event event;
       pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING,
               &packets[0].timestamp,
               codec);
       pjmedia_event_publish(NULL, codec, &event, 0);
    } else if (res != VPX_CODEC_OK) {
        PJ_LOG(1,
                (THIS_FILE, "Failed to decode packet : %s of size %d", vpx_codec_err_to_string(res), vpx->dec_frame_len));
        /* TODO : better error code. Map with res? */
        return PJ_SUCCESS;
    }

    /* No need to loop here for first implementation */
    img = vpx_codec_get_frame(&vpx->decoder, &iter);
    if (img != NULL) {
        /* We have a frame available */
        pj_vpx_codec_decode_whole(codec, img, &packets[0].timestamp, out_size, output);
    }

    return PJ_SUCCESS;
}