Esempio n. 1
0
void
pp_resource_unref(PP_Resource resource)
{
    int ref_cnt = 0;

    pthread_mutex_lock(&res_tbl_lock);
    struct pp_resource_generic_s *ptr = g_hash_table_lookup(res_tbl, GINT_TO_POINTER(resource));
    if (ptr) {
        ref_cnt = --ptr->ref_cnt;

        // reference count should always be non-negative
        if (ref_cnt < 0)
            trace_error("%s, logic error, ref count gone negative\n", __func__);

        // prevent from being destroyed twice
        if (ref_cnt <= 0)
            g_hash_table_remove(res_tbl, GINT_TO_POINTER(resource));
    }
    pthread_mutex_unlock(&res_tbl_lock);

    if (!ptr)
        return;

    if (ref_cnt <= 0) {
        switch (ptr->resource_type) {
        case PP_RESOURCE_URL_LOADER:
            ppb_url_loader_destroy(ptr);
            break;
        case PP_RESOURCE_URL_RESPONSE_INFO:
            ppb_url_response_info_destroy(ptr);
            break;
        case PP_RESOURCE_URL_REQUEST_INFO:
            ppb_url_request_info_destroy(ptr);
            break;
        case PP_RESOURCE_IMAGE_DATA:
            ppb_image_data_destroy(ptr);
            break;
        case PP_RESOURCE_GRAPHICS2D:
            ppb_graphics2d_destroy(ptr);
            break;
        case PP_RESOURCE_GRAPHICS3D:
            ppb_graphics3d_destroy(ptr);
            break;
        case PP_RESOURCE_BROWSER_FONT:
            ppb_browser_font_destroy(ptr);
            break;
        case PP_RESOURCE_AUDIO_CONFIG:
            ppb_audio_config_destroy(ptr);
            break;
        case PP_RESOURCE_AUDIO:
            ppb_audio_destroy(ptr);
            break;
        case PP_RESOURCE_INPUT_EVENT:
            ppb_input_event_destroy(ptr);
            break;
        case PP_RESOURCE_FLASH_FONT_FILE:
            ppb_flash_font_file_destroy(ptr);
            break;
        case PP_RESOURCE_VIDEO_CAPTURE:
            ppb_video_capture_destroy(ptr);
            break;
        case PP_RESOURCE_AUDIO_INPUT:
            ppb_audio_input_destroy(ptr);
            break;
        case PP_RESOURCE_FLASH_MENU:
            ppb_flash_menu_destroy(ptr);
            break;
        case PP_RESOURCE_FLASH_MESSAGE_LOOP:
            ppb_flash_message_loop_destroy(ptr);
            break;
        case PP_RESOURCE_TCP_SOCKET:
            ppb_tcp_socket_destroy(ptr);
            break;
        case PP_RESOURCE_FILE_REF:
            ppb_file_ref_destroy(ptr);
            break;
        case PP_RESOURCE_FILE_IO:
            ppb_file_io_destroy(ptr);
            break;
        case PP_RESOURCE_MESSAGE_LOOP:
            ppb_message_loop_destroy(ptr);
            break;
        case PP_RESOURCE_FLASH_DRM:
            ppb_flash_drm_destroy(ptr);
            break;
        case PP_RESOURCE_VIDEO_DECODER:
            ppb_video_decoder_destroy_priv(ptr);
            break;
        case PP_RESOURCE_BUFFER:
            ppb_buffer_destroy(ptr);
            break;
        case PP_RESOURCE_FILE_CHOOSER:
            ppb_file_chooser_destroy(ptr);
            break;
        case PP_RESOURCE_UDP_SOCKET:
            ppb_udp_socket_destroy(ptr);
            break;
        case PP_RESOURCE_X509_CERTIFICATE:
            ppb_x509_certificate_destroy(ptr);
            break;
        case PP_RESOURCE_FONT:
            ppb_font_destroy(ptr);
            break;
        case PP_RESOURCE_DEVICE_REF:
            ppb_device_ref_destroy(ptr);
            break;
        case PP_RESOURCE_HOST_RESOLVER:
            ppb_host_resolver_destroy(ptr);
            break;
        default:
            break;
        }
    }

    // finally, free memory occupied by resource
    if (ref_cnt <= 0)
        g_slice_free1(sizeof(union pp_largest_u), ptr);

    if (config.quirks.dump_resource_histogram) {
        time_t current_time = time(NULL);
        static uintptr_t throttling = 0;

        if (current_time % 5 == 0) {
            if (!throttling) {
                int counts[PP_RESOURCE_TYPES_COUNT + 1] = {};

                pthread_mutex_lock(&res_tbl_lock);
                g_hash_table_foreach(res_tbl, count_resources_cb, counts);
                pthread_mutex_unlock(&res_tbl_lock);

                trace_error("-- %10lu ------------\n", (unsigned long)current_time);
                for (int k = 0; k < PP_RESOURCE_TYPES_COUNT; k ++)
                    if (counts[k] > 0)
                        trace_error("counts[%2d] = %d\n", k, counts[k]);
                if (counts[PP_RESOURCE_TYPES_COUNT] > 0)
                    trace_error("%d unknown resources (should never happen)\n",
                                counts[PP_RESOURCE_TYPES_COUNT]);
                trace_error("==========================\n");
                throttling = 1;
            }
        } else {
            throttling = 0;
        }
    }
}
PP_Resource
ppb_video_decoder_create(PP_Instance instance, PP_Resource context, PP_VideoDecoder_Profile profile)
{
    if (!config.enable_hwdec) {
        trace_info_f("      hardware-accelerated decoding was disabled in config file\n");
        return 0;
    }

    if (!display.va_available) {
        trace_info_f("      no hw acceleration available\n");
        return 0;
    }

    if (!display.glXBindTexImageEXT) {
        trace_info_f("      no glXBindTexImageEXT available\n");
        return 0;
    }

    switch (profile) {
    case PP_VIDEODECODER_H264PROFILE_BASELINE:
    case PP_VIDEODECODER_H264PROFILE_MAIN:
    case PP_VIDEODECODER_H264PROFILE_EXTENDED:
    case PP_VIDEODECODER_H264PROFILE_HIGH:
        // pass, there is an implementation below
        break;

    case PP_VIDEODECODER_H264PROFILE_NONE:
    case PP_VIDEODECODER_H264PROFILE_HIGH10PROFILE:
    case PP_VIDEODECODER_H264PROFILE_HIGH422PROFILE:
    case PP_VIDEODECODER_H264PROFILE_HIGH444PREDICTIVEPROFILE:
    case PP_VIDEODECODER_H264PROFILE_SCALABLEBASELINE:
    case PP_VIDEODECODER_H264PROFILE_SCALABLEHIGH:
    case PP_VIDEODECODER_H264PROFILE_STEREOHIGH:
    case PP_VIDEODECODER_H264PROFILE_MULTIVIEWHIGH:
    case PP_VIDEODECODER_VP8PROFILE_ANY:
    case PP_VIDEODECODER_PROFILE_UNKNOWN:
    default:
        trace_error("%s, profile %d is not supported\n", __func__, profile);
        return 0;
    }

    const struct PPP_VideoDecoder_Dev_0_11 *ppp_video_decoder_dev = NULL;
    struct pp_instance_s *pp_i = tables_get_pp_instance(instance);
    if (!pp_i) {
        trace_error("%s, bad instance\n", __func__);
        return 0;
    }

    ppp_video_decoder_dev = ppp_get_interface(PPP_VIDEODECODER_DEV_INTERFACE);
    if (!ppp_video_decoder_dev) {
        trace_error("%s, no viable %s\n", __func__, PPP_VIDEODECODER_DEV_INTERFACE);
        return 0;
    }

    if (pp_resource_get_type(context) != PP_RESOURCE_GRAPHICS3D) {
        trace_error("%s, bad resource\n", __func__);
        return 0;
    }

    PP_Resource video_decoder = pp_resource_allocate(PP_RESOURCE_VIDEO_DECODER, pp_i);
    struct pp_video_decoder_s *vd = pp_resource_acquire(video_decoder, PP_RESOURCE_VIDEO_DECODER);
    if (!vd) {
        trace_error("%s, resource allocation failed\n", __func__);
        return 0;
    }

    vd->orig_graphics3d = pp_resource_ref(context);
    vd->ppp_video_decoder_dev = ppp_video_decoder_dev;

    // create auxiliary GL context
    int32_t attribs[] = {
        PP_GRAPHICS3DATTRIB_WIDTH,      32,     // dimensions can be arbitrary
        PP_GRAPHICS3DATTRIB_HEIGHT,     32,
        PP_GRAPHICS3DATTRIB_RED_SIZE,   8,
        PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
        PP_GRAPHICS3DATTRIB_BLUE_SIZE,  8,
        PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
        PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 16,
        GLX_Y_INVERTED_EXT,             True,
        GLX_BIND_TO_TEXTURE_RGBA_EXT,   True,
        PP_GRAPHICS3DATTRIB_NONE,
    };

    vd->graphics3d = ppb_graphics3d_create(vd->instance->id, vd->orig_graphics3d, attribs);
    if (!vd->graphics3d) {
        trace_error("%s, can't create graphics3d context\n", __func__);
        goto err_1;
    }

    vd->codec_id = AV_CODEC_ID_H264;        // TODO: other codecs
    vd->avcodec = avcodec_find_decoder(vd->codec_id);
    if (!vd->avcodec) {
        trace_error("%s, can't create codec\n", __func__);
        goto err_1;
    }

    vd->avparser = av_parser_init(vd->codec_id);
    if (!vd->avparser) {
        trace_error("%s, can't create parser\n", __func__);
        goto err_1;
    }

    vd->avctx = avcodec_alloc_context3(vd->avcodec);
    if (!vd->avctx) {
        trace_error("%s, can't create codec context\n", __func__);
        goto err_1;
    }

    if (vd->avcodec->capabilities & CODEC_CAP_TRUNCATED) {
        trace_info("%s, codec have CODEC_CAP_TRUNCATED\n", __func__);
        vd->avctx->flags |= CODEC_FLAG_TRUNCATED;
    }

    vd->avctx->opaque = vd;
    vd->avctx->thread_count = 1;
    vd->avctx->get_format = get_format;

#if AVCTX_HAVE_REFCOUNTED_BUFFERS
    vd->avctx->get_buffer2 = get_buffer2;
    vd->avctx->refcounted_frames = 1;
#else
    vd->avctx->get_buffer = get_buffer;
    vd->avctx->release_buffer = release_buffer;
#endif

    if (avcodec_open2(vd->avctx, vd->avcodec, NULL) < 0) {
        trace_error("%s, can't open codec\n", __func__);
        goto err_1;
    }

    vd->avframe = av_frame_alloc();
    if (!vd->avframe) {
        trace_error("%s, can't alloc frame\n", __func__);
        goto err_1;
    }

    pp_resource_release(video_decoder);
    return video_decoder;

err_1:
    ppb_video_decoder_destroy_priv(vd);

    pp_resource_release(video_decoder);
    pp_resource_expunge(video_decoder);
    return 0;
}