static PP_Resource do_ppb_audio_create(PP_Instance instance, PP_Resource audio_config, PPB_Audio_Callback_1_0 audio_callback_1_0, PPB_Audio_Callback audio_callback_1_1, void *user_data) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } if (!audio_callback_1_0 && !audio_callback_1_1) return PP_ERROR_BADARGUMENT; PP_Resource audio = pp_resource_allocate(PP_RESOURCE_AUDIO, pp_i); struct pp_audio_s *a = pp_resource_acquire(audio, PP_RESOURCE_AUDIO); if (!a) { trace_error("%s, resource allocation failure\n", __func__); return 0; } struct pp_audio_config_s *ac = pp_resource_acquire(audio_config, PP_RESOURCE_AUDIO_CONFIG); if (!ac) { trace_error("%s, bad audio config\n", __func__); goto err; } a->sample_rate = ac->sample_rate; a->sample_frame_count = ac->sample_frame_count; pp_resource_release(audio_config); a->callback_1_0 = audio_callback_1_0; a->callback_1_1 = audio_callback_1_1; a->user_data = user_data; a->stream_ops = audio_select_implementation(); if (a->stream_ops == NULL) { trace_error("%s, no viable audio implementation\n", __func__); goto err; } a->stream = a->stream_ops->create_playback_stream(a->sample_rate, a->sample_frame_count, playback_cb, a); if (!a->stream) { trace_error("%s, can't create playback stream\n", __func__); goto err; } pp_resource_release(audio); return audio; err: pp_resource_release(audio); pp_resource_expunge(audio); return 0; }
PP_Resource ppb_graphics3d_create(PP_Instance instance, PP_Resource share_context, const int32_t attrib_list[]) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } PP_Resource context = pp_resource_allocate(PP_RESOURCE_GRAPHICS3D, pp_i); struct pp_graphics3d_s *g3d = pp_resource_acquire(context, PP_RESOURCE_GRAPHICS3D); if (!g3d) { trace_error("%s, can't create context\n", __func__); return 0; } int attrib_len = 0; while (attrib_list[attrib_len] != PP_GRAPHICS3DATTRIB_NONE) { attrib_len += 2; } attrib_len ++; EGLint *egl_attribute_list = calloc(attrib_len + 3 * 2, sizeof(EGLint)); int done = 0, k1 = 0, k2 = 0; egl_attribute_list[k2++] = EGL_SURFACE_TYPE; egl_attribute_list[k2++] = EGL_PIXMAP_BIT | EGL_WINDOW_BIT; egl_attribute_list[k2++] = EGL_RENDERABLE_TYPE; egl_attribute_list[k2++] = EGL_OPENGL_ES2_BIT; while (!done) { switch (attrib_list[k1]) { case PP_GRAPHICS3DATTRIB_HEIGHT: g3d->height = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_WIDTH: g3d->width = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE: case PP_GRAPHICS3DATTRIB_SWAP_BEHAVIOR: // TODO: save these values k1 += 2; break; case PP_GRAPHICS3DATTRIB_NONE: egl_attribute_list[k2++] = EGL_NONE; done = 1; break; case PP_GRAPHICS3DATTRIB_ALPHA_SIZE: egl_attribute_list[k2++] = EGL_ALPHA_SIZE; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_BLUE_SIZE: egl_attribute_list[k2++] = EGL_BLUE_SIZE; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_GREEN_SIZE: egl_attribute_list[k2++] = EGL_GREEN_SIZE; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_RED_SIZE: egl_attribute_list[k2++] = EGL_RED_SIZE; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_DEPTH_SIZE: egl_attribute_list[k2++] = EGL_DEPTH_SIZE; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_STENCIL_SIZE: egl_attribute_list[k2++] = EGL_STENCIL_SIZE; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_SAMPLES: egl_attribute_list[k2++] = EGL_SAMPLES; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS: egl_attribute_list[k2++] = EGL_SAMPLE_BUFFERS; egl_attribute_list[k2++] = attrib_list[k1 + 1]; k1 += 2; break; default: // skip unknown attribute trace_error("%s, unknown attribute 0x%x\n", __func__, attrib_list[k1]); k1 += 1; break; } } pthread_mutex_lock(&display.lock); int nconfigs = 0; EGLBoolean ret = eglChooseConfig(display.egl, egl_attribute_list, &g3d->egl_config, 1, &nconfigs); free(egl_attribute_list); if (!ret) { trace_error("%s, eglChooseConfig returned FALSE\n", __func__); goto err; } if (nconfigs != 1) { trace_error("%s, eglChooseConfig returned %d configs, expected 1\n", __func__, nconfigs); goto err; } // TODO: support shared_context EGLint ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; g3d->glc = eglCreateContext(display.egl, g3d->egl_config, EGL_NO_CONTEXT, ctxattr); if (g3d->glc == EGL_NO_CONTEXT) { trace_error("%s, eglCreateContext returned EGL_NO_CONTEXT\n", __func__); goto err; } g3d->pixmap = XCreatePixmap(display.x, DefaultRootWindow(display.x), g3d->width, g3d->height, DefaultDepth(display.x, 0)); g3d->egl_surf = eglCreatePixmapSurface(display.egl, g3d->egl_config, g3d->pixmap, NULL); if (g3d->egl_surf == EGL_NO_SURFACE) { trace_error("%s, failed to create EGL pixmap surface\n", __func__); goto err; } ret = eglMakeCurrent(display.egl, g3d->egl_surf, g3d->egl_surf, g3d->glc); if (!ret) { trace_error("%s, eglMakeCurrent failed\n", __func__); goto err; } // clear surface glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); if (pp_i->is_transparent) { // create texture for plugin content glGenTextures(1, &g3d->tex_front); glBindTexture(GL_TEXTURE_2D, g3d->tex_front); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if (create_presentation_egl_context(g3d) != 0) { trace_error("%s, can't create EGL context for transparency processing\n", __func__); goto err; } } eglMakeCurrent(display.egl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); g3d->sub_maps = g_hash_table_new(g_direct_hash, g_direct_equal); pthread_mutex_unlock(&display.lock); pp_resource_release(context); return context; err: pthread_mutex_unlock(&display.lock); pp_resource_release(context); pp_resource_expunge(context); return 0; }
PP_Resource ppb_graphics3d_create(PP_Instance instance, PP_Resource share_context, const int32_t attrib_list[]) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } GLXContext share_glc = (share_context == 0) ? NULL : peek_gl_context(share_context); // check for required GLX extensions #if HAVE_GLES2 if (!display.glx_arb_create_context || !display.glx_arb_create_context_profile || !display.glx_ext_create_context_es2_profile) { trace_warning("%s, some of GLX_ARB_create_context, GLX_ARB_create_context_profile, " "GLX_EXT_create_context_es2_profile missing\n", __func__); return 0; } if (!display.glXCreateContextAttribsARB) { trace_warning("%s, no glXCreateContextAttribsARB found\n", __func__); return 0; } #endif PP_Resource context = pp_resource_allocate(PP_RESOURCE_GRAPHICS3D, pp_i); struct pp_graphics3d_s *g3d = pp_resource_acquire(context, PP_RESOURCE_GRAPHICS3D); if (!g3d) { trace_error("%s, can't create context\n", __func__); return 0; } int attrib_len = 0; while (attrib_list[attrib_len] != PP_GRAPHICS3DATTRIB_NONE) { attrib_len += 2; } attrib_len ++; int *cfg_attrs = calloc(attrib_len + 3 * 2, sizeof(int)); int k2 = 0; cfg_attrs[k2++] = GLX_X_RENDERABLE; cfg_attrs[k2++] = True; cfg_attrs[k2++] = GLX_DRAWABLE_TYPE; cfg_attrs[k2++] = GLX_WINDOW_BIT | GLX_PIXMAP_BIT; int done = 0; int k1 = 0; while (!done) { switch (attrib_list[k1]) { case PP_GRAPHICS3DATTRIB_HEIGHT: g3d->height = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_WIDTH: g3d->width = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE: case PP_GRAPHICS3DATTRIB_SWAP_BEHAVIOR: // TODO: save these values k1 += 2; break; case PP_GRAPHICS3DATTRIB_NONE: cfg_attrs[k2++] = None; done = 1; break; case PP_GRAPHICS3DATTRIB_ALPHA_SIZE: cfg_attrs[k2++] = GLX_ALPHA_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_BLUE_SIZE: cfg_attrs[k2++] = GLX_BLUE_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_GREEN_SIZE: cfg_attrs[k2++] = GLX_GREEN_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_RED_SIZE: cfg_attrs[k2++] = GLX_RED_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_DEPTH_SIZE: cfg_attrs[k2++] = GLX_DEPTH_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_STENCIL_SIZE: cfg_attrs[k2++] = GLX_STENCIL_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_SAMPLES: cfg_attrs[k2++] = GLX_SAMPLES; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS: cfg_attrs[k2++] = GLX_SAMPLE_BUFFERS; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case GLX_Y_INVERTED_EXT: cfg_attrs[k2++] = GLX_Y_INVERTED_EXT; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case GLX_BIND_TO_TEXTURE_RGBA_EXT: cfg_attrs[k2++] = GLX_BIND_TO_TEXTURE_RGBA_EXT; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; default: // skip unknown attribute trace_error("%s, unknown attribute 0x%x\n", __func__, attrib_list[k1]); k1 += 1; break; } } pthread_mutex_lock(&display.lock); int screen = DefaultScreen(display.x); int nconfigs = 0; GLXFBConfig *fb_cfgs = glXChooseFBConfig(display.x, screen, cfg_attrs, &nconfigs); free(cfg_attrs); if (!fb_cfgs) { trace_error("%s, glXChooseFBConfig returned NULL\n", __func__); goto err; } trace_info_f("%s, glXChooseFBConfig returned %d configs, choosing first one\n", __func__, nconfigs); g3d->fb_config = fb_cfgs[0]; XFree(fb_cfgs); #if HAVE_GLES2 // create context implementing OpenGL ES 2.0 const int ctx_attrs[] = { GLX_RENDER_TYPE, GLX_RGBA_TYPE, GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, None, }; #else // create context implementing OpenGL 2.0 // OpenGL ES 2.0 will be emulated with help of shader translator const int ctx_attrs[] = { GLX_RENDER_TYPE, GLX_RGBA_TYPE, GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None, }; #endif if (display.glXCreateContextAttribsARB) { g3d->glc = display.glXCreateContextAttribsARB(display.x, g3d->fb_config, share_glc, True, ctx_attrs); if (!g3d->glc) trace_warning("%s, glXCreateContextAttribsARB returned NULL\n", __func__); } else { g3d->glc = NULL; } if (!g3d->glc) { // if glXCreateContextAttribsARB is not present or returned NULL, // request any GL context g3d->glc = glXCreateNewContext(display.x, g3d->fb_config, GLX_RGBA_TYPE, share_glc, True); if (!g3d->glc) { trace_error("%s, glXCreateNewContext returned NULL\n", __func__); goto err; } } g3d->depth = pp_i->is_transparent ? 32 : DefaultDepth(display.x, screen); switch (g3d->depth) { case 24: g3d->xr_pictfmt = display.pictfmt_rgb24; break; case 32: g3d->xr_pictfmt = display.pictfmt_argb32; break; default: trace_error("%s, unsupported g3d->depth (%d)\n", __func__, g3d->depth); goto err; } g3d->pixmap = XCreatePixmap(display.x, DefaultRootWindow(display.x), g3d->width, g3d->height, g3d->depth); g3d->glx_pixmap = glXCreatePixmap(display.x, g3d->fb_config, g3d->pixmap, NULL); if (g3d->glx_pixmap == None) { trace_error("%s, failed to create GLX pixmap\n", __func__); goto err; } XFlush(display.x); g3d->xr_pict = XRenderCreatePicture(display.x, g3d->pixmap, g3d->xr_pictfmt, 0, 0); int ret = glXMakeCurrent(display.x, g3d->glx_pixmap, g3d->glc); if (!ret) { trace_error("%s, glXMakeCurrent failed\n", __func__); goto err; } // clear surface glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glXMakeCurrent(display.x, None, NULL); g3d->sub_maps = g_hash_table_new(g_direct_hash, g_direct_equal); pthread_mutex_unlock(&display.lock); pp_resource_release(context); return context; err: pthread_mutex_unlock(&display.lock); pp_resource_release(context); pp_resource_expunge(context); return 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; }