PP_Resource ppb_graphics2d_create(PP_Instance instance, const struct PP_Size *size, PP_Bool is_always_opaque) { 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 graphics_2d = pp_resource_allocate(PP_RESOURCE_GRAPHICS2D, pp_i); struct pp_graphics2d_s *g2d = pp_resource_acquire(graphics_2d, PP_RESOURCE_GRAPHICS2D); if (!g2d) { trace_error("%s, can't create graphics2d resource\n", __func__); return 0; } g2d->is_always_opaque = is_always_opaque; g2d->scale = config.device_scale; g2d->width = size->width; g2d->height = size->height; g2d->stride = 4 * size->width; g2d->scaled_width = g2d->width * g2d->scale + 0.5; g2d->scaled_height = g2d->height * g2d->scale + 0.5; g2d->scaled_stride = 4 * g2d->scaled_width; g2d->data = calloc(g2d->stride * g2d->height, 1); g2d->second_buffer = calloc(g2d->scaled_stride * g2d->scaled_height, 1); if (!g2d->data || !g2d->second_buffer) { trace_warning("%s, can't allocate memory\n", __func__); free_and_nullify(g2d->data); free_and_nullify(g2d->second_buffer); pp_resource_release(graphics_2d); ppb_core_release_resource(graphics_2d); return 0; } g2d->cairo_surf = cairo_image_surface_create_for_data((unsigned char *)g2d->data, CAIRO_FORMAT_ARGB32, g2d->width, g2d->height, g2d->stride); g2d->task_list = NULL; if (pp_i->is_transparent) { // we need XRender picture (which in turn requires X Pixmap) to alpha blend // our images with existing pixmap provided by the browser. This is only needed // is instance is transparent, therefore depth is always 32-bit. pthread_mutex_lock(&display.lock); g2d->pixmap = XCreatePixmap(display.x, DefaultRootWindow(display.x), g2d->scaled_width, g2d->scaled_height, 32); XFlush(display.x); g2d->xr_pict = XRenderCreatePicture(display.x, g2d->pixmap, display.pictfmt_argb32, 0, 0); g2d->gc = XCreateGC(display.x, g2d->pixmap, 0, 0); XFlush(display.x); pthread_mutex_unlock(&display.lock); } pp_resource_release(graphics_2d); return graphics_2d; }
void ppb_graphics2d_destroy(void *p) { if (!p) return; struct pp_graphics2d_s *g2d = p; free_and_nullify(g2d, data); free_and_nullify(g2d, second_buffer); if (g2d->cairo_surf) { cairo_surface_destroy(g2d->cairo_surf); g2d->cairo_surf = NULL; } }
static void ppb_url_loader_destroy(void *p) { if (!p) return; struct pp_url_loader_s *ul = p; if (ul->fd >= 0) { close(ul->fd); ul->fd = -1; } free_and_nullify(ul->headers); free_and_nullify(ul->url); free_and_nullify(ul->status_line); free_and_nullify(ul->request_headers); free_and_nullify(ul->custom_referrer_url); free_and_nullify(ul->custom_content_transfer_encoding); free_and_nullify(ul->custom_user_agent); free_and_nullify(ul->target); post_data_free(ul->post_data); ul->post_data = NULL; while (ul->read_tasks) { GList *llink = g_list_first(ul->read_tasks); struct url_loader_read_task_s *rt = llink->data; ul->read_tasks = g_list_delete_link(ul->read_tasks, llink); g_slice_free1(sizeof(*rt), rt); } }
static void ppb_url_request_info_destroy(void *p) { struct pp_url_request_info_s *ri = p; if (!ri) return; free_and_nullify(ri->url); free_and_nullify(ri->headers); free_and_nullify(ri->custom_referrer_url); free_and_nullify(ri->custom_content_transfer_encoding); free_and_nullify(ri->custom_user_agent); post_data_free(ri->post_data); ri->post_data = NULL; }
static void ppb_host_resolver_destroy(void *ptr) { struct pp_host_resolver_s *hr = ptr; free_and_nullify(hr->addrs); }
void ppb_video_capture_destroy(void *p) { struct pp_video_capture_s *vc = p; if (vc->fd != -1) { v4l2_close(vc->fd); vc->fd = -1; } if (vc->buffers) { for (uint32_t k = 0; k < vc->buffer_count; k ++) ppb_core_release_resource(vc->buffers[k]); } free_and_nullify(vc->buffers); free_and_nullify(vc->buffer_is_free); }
static void ppb_video_decoder_destroy_priv(void *p) { struct pp_video_decoder_s *vd = p; if (vd->orig_graphics3d) { pp_resource_unref(vd->orig_graphics3d); vd->orig_graphics3d = 0; } if (vd->graphics3d) { pp_resource_unref(vd->graphics3d); vd->graphics3d = 0; } if (vd->avparser) { av_parser_close(vd->avparser); vd->avparser = NULL; } if (vd->avctx) avcodec_free_context(&vd->avctx); if (vd->avframe) av_frame_free(&vd->avframe); if (vd->va_context.context_id) { vaDestroyContext(display.va, vd->va_context.context_id); vd->va_context.context_id = 0; } if (vd->va_context.config_id) { vaDestroyConfig(display.va, vd->va_context.config_id); vd->va_context.config_id = 0; } vaDestroySurfaces(display.va, vd->surfaces, MAX_VIDEO_SURFACES); for (uintptr_t k = 0; k < MAX_VIDEO_SURFACES; k ++) { vd->surfaces[k] = VA_INVALID_SURFACE; vd->surface_used[k] = 0; } for (uintptr_t k = 0; k < vd->buffer_count; k ++) { vd->ppp_video_decoder_dev->DismissPictureBuffer(vd->instance->id, vd->self_id, vd->buffers[k].id); pthread_mutex_lock(&display.lock); glXDestroyPixmap(display.x, vd->buffers[k].glx_pixmap); XFreePixmap(display.x, vd->buffers[k].pixmap); pthread_mutex_unlock(&display.lock); } vd->buffer_count = 0; vd->buffers_were_requested = 0; free_and_nullify(vd->buffers); }
void ppb_url_loader_close(PP_Resource loader) { struct pp_url_loader_s *ul = pp_resource_acquire(loader, PP_RESOURCE_URL_LOADER); if (!ul) { trace_error("%s, bad resource\n", __func__); return; } if (ul->fd >= 0) { close(ul->fd); ul->fd = -1; } free_and_nullify(ul, headers); free_and_nullify(ul, url); pp_resource_release(loader); return; }
static void ppb_input_event_destroy(void *p) { struct pp_input_event_s *ie = p; ppb_var_release(ie->code); ppb_var_release(ie->text); free_and_nullify(ie->segment_offsets); }
PP_Resource ppb_graphics2d_create(PP_Instance instance, const struct PP_Size *size, PP_Bool is_always_opaque) { 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 graphics_2d = pp_resource_allocate(PP_RESOURCE_GRAPHICS2D, pp_i); struct pp_graphics2d_s *g2d = pp_resource_acquire(graphics_2d, PP_RESOURCE_GRAPHICS2D); if (!g2d) { trace_error("%s, can't create graphics2d resource\n", __func__); return 0; } g2d->is_always_opaque = is_always_opaque; g2d->scale = 1.0; g2d->width = size->width; g2d->height = size->height; g2d->stride = 4 * size->width; g2d->scaled_width = g2d->width; g2d->scaled_height = g2d->height; g2d->scaled_stride = g2d->stride; g2d->data = calloc(g2d->stride * g2d->height, 1); g2d->second_buffer = calloc(g2d->scaled_stride * g2d->scaled_height, 1); if (!g2d->data || !g2d->second_buffer) { trace_warning("%s, can't allocate memory\n", __func__); free_and_nullify(g2d, data); free_and_nullify(g2d, second_buffer); pp_resource_release(graphics_2d); ppb_core_release_resource(graphics_2d); return 0; } g2d->cairo_surf = cairo_image_surface_create_for_data((unsigned char *)g2d->data, CAIRO_FORMAT_ARGB32, g2d->width, g2d->height, g2d->stride); g2d->task_list = NULL; pp_resource_release(graphics_2d); return graphics_2d; }
void finalize_config( FGLS_config_t *cf ) { // Free databel headers (fvi) free_databel_fvi( &cf->Phi_fvi ); free_databel_fvi( &cf->XL_fvi ); free_databel_fvi( &cf->XR_fvi ); free_databel_fvi( &cf->Y_fvi ); // Free in-core data buffers free_and_nullify( &cf->ests ); cf->h2 = NULL; cf->sigma2 = NULL; cf->res_sigma2 = NULL; cf->beta_ests = NULL; free_and_nullify( &cf->Phi ); free_and_nullify( &cf->XL ); free_and_nullify( &cf->ZtXL ); free_and_nullify( &cf->Z ); free_and_nullify( &cf->W ); // Close out-of-core data files close_and_nullify( &cf->XR ); close_and_nullify( &cf->ZtXR ); close_and_nullify( &cf->Y ); close_and_nullify( &cf->ZtY ); close_and_nullify( &cf->B ); // close_and_nullify( &cf->V ); }
static void ppb_graphics2d_destroy(void *p) { if (!p) return; struct pp_graphics2d_s *g2d = p; free_and_nullify(g2d->data); free_and_nullify(g2d->second_buffer); if (g2d->cairo_surf) { cairo_surface_destroy(g2d->cairo_surf); g2d->cairo_surf = NULL; } if (g2d->instance->is_transparent) { pthread_mutex_lock(&display.lock); XRenderFreePicture(display.x, g2d->xr_pict); XFreePixmap(display.x, g2d->pixmap); XFreeGC(display.x, g2d->gc); pthread_mutex_unlock(&display.lock); } }
void ppb_image_data_destroy(void *p) { if (!p) return; struct pp_image_data_s *id = p; if (id->cairo_surf) { cairo_surface_destroy(id->cairo_surf); id->cairo_surf = NULL; } free_and_nullify(id, data); }
void ppb_url_loader_destroy(void *p) { if (!p) return; struct pp_url_loader_s *ul = p; if (ul->fd >= 0) { close(ul->fd); ul->fd = -1; } free_and_nullify(ul, headers); free_and_nullify(ul, url); free_and_nullify(ul, status_line); free_and_nullify(ul, request_headers); free_and_nullify(ul, custom_referrer_url); free_and_nullify(ul, custom_content_transfer_encoding); free_and_nullify(ul, custom_user_agent); free_and_nullify(ul, post_data); free_and_nullify(ul, target); }
void ppb_url_request_info_destroy(void *p) { struct pp_url_request_info_s *ri = p; if (!ri) return; free_and_nullify(ri, url); free_and_nullify(ri, headers); free_and_nullify(ri, custom_referrer_url); free_and_nullify(ri, custom_content_transfer_encoding); free_and_nullify(ri, custom_user_agent); free_and_nullify(ri, post_data); }
PP_Bool ppb_url_request_info_append_data_to_body(PP_Resource request, const void *data, uint32_t len) { struct pp_url_request_info_s *ri = pp_resource_acquire(request, PP_RESOURCE_URL_REQUEST_INFO); PP_Bool retval = PP_FALSE; free_and_nullify(ri, post_data); ri->post_len = 0; ri->post_data = malloc(len); if (ri->post_data) { memcpy(ri->post_data, data, len); ri->post_len = len; retval = PP_TRUE; } else { retval = PP_FALSE; } pp_resource_release(request); return retval; }
PP_Bool ppb_url_request_info_set_property(PP_Resource request, PP_URLRequestProperty property, struct PP_Var value) { const char *tmp, *tmp2; PP_Bool retval = PP_TRUE; struct pp_url_request_info_s *ri = pp_resource_acquire(request, PP_RESOURCE_URL_REQUEST_INFO); if (!ri) { trace_error("%s, bad resource\n", __func__); return PP_FALSE; } #define ENSURE_TYPE(vartype) if (value.type != vartype) { retval = PP_FALSE; break; } switch (property) { case PP_URLREQUESTPROPERTY_URL: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->url); tmp = ppb_var_var_to_utf8(value, NULL); tmp2 = ltrim(tmp); ri->url = strdup(tmp2); ri->is_immediate_javascript = (strncasecmp(tmp2, "javascript:", strlen("javascript:"))==0); break; case PP_URLREQUESTPROPERTY_METHOD: ENSURE_TYPE(PP_VARTYPE_STRING); tmp = ppb_var_var_to_utf8(value, NULL); if (strcmp(tmp, "GET") == 0) { ri->method = PP_METHOD_GET; } else if (strcmp(tmp, "POST") == 0) { ri->method = PP_METHOD_POST; } else { trace_warning("%s, unknown method %s\n", __func__, tmp); ri->method = PP_METHOD_UNKNOWN; } break; case PP_URLREQUESTPROPERTY_HEADERS: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->headers); ri->headers = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_STREAMTOFILE: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->stream_to_file = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->follow_redirects = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->record_download_progress = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->record_upload_progress = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_referrer_url); ri->custom_referrer_url = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->allow_cross_origin_requests = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->allow_credentials = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_content_transfer_encoding); ri->custom_content_transfer_encoding = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD: ENSURE_TYPE(PP_VARTYPE_INT32); ri->prefetch_buffer_upper_threshold = value.value.as_int; break; case PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD: ENSURE_TYPE(PP_VARTYPE_INT32); ri->prefetch_buffer_lower_threshold = value.value.as_int; break; case PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_user_agent); ri->custom_user_agent = strdup(ppb_var_var_to_utf8(value, NULL)); break; default: trace_error("%s, unknown url request property %d\n", __func__, property); retval = PP_FALSE; break; } pp_resource_release(request); return retval; }
int32_t ppb_url_loader_follow_redirect(PP_Resource loader, struct PP_CompletionCallback callback) { struct pp_url_loader_s *ul = pp_resource_acquire(loader, PP_RESOURCE_URL_LOADER); if (!ul) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } char *new_url = nullsafe_strdup(ul->redirect_url); free_and_nullify(ul, url); free_and_nullify(ul, redirect_url); free_and_nullify(ul, status_line); free_and_nullify(ul, headers); free_and_nullify(ul, request_headers); if (ul->fd >= 0) { close(ul->fd); ul->fd = -1; } // abort further handling of the NPStream if (ul->np_stream) { ul->np_stream->pdata = NULL; ul->np_stream = NULL; } ul->fd = open_temporary_file(); ul->url = new_url; ul->read_pos = 0; ul->method = PP_METHOD_GET; ul->ccb = callback; struct url_loader_open_param_s *p = g_slice_alloc(sizeof(*p)); p->url = ul->url; p->loader = loader; p->instance_id = ul->instance->id; p->method = ul->method; p->request_headers = ul->request_headers; p->custom_referrer_url = ul->custom_referrer_url; p->custom_content_transfer_encoding = ul->custom_content_transfer_encoding; p->custom_user_agent = ul->custom_user_agent; p->target = NULL; p->post_len = 0; p->post_data = NULL; p->m_loop = ppb_message_loop_get_current(); p->depth = ppb_message_loop_get_depth(p->m_loop) + 1; ppb_message_loop_post_work(p->m_loop, PP_MakeCCB(_url_loader_open_comt, p), 0); ppb_message_loop_run_nested(p->m_loop); pp_resource_release(loader); int retval = p->retval; g_slice_free1(sizeof(*p), p); if (retval != NPERR_NO_ERROR) return PP_ERROR_FAILED; if (callback.func == NULL) { int done = 0; while (!done) { ul = pp_resource_acquire(loader, PP_RESOURCE_URL_LOADER); if (ul) { done = ul->finished_loading; pp_resource_release(loader); } else { break; } printf("waitin'\n"); usleep(10000); } return PP_OK; } return PP_OK_COMPLETIONPENDING; }
int32_t ppb_video_capture_open(PP_Resource video_capture, PP_Resource device_ref, const struct PP_VideoCaptureDeviceInfo_Dev *requested_info, uint32_t buffer_count, struct PP_CompletionCallback callback) { int32_t result; struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } const char *capture_device = default_capture_device; struct PP_Var longname = ppb_device_ref_get_longname(device_ref); if (longname.type == PP_VARTYPE_STRING) capture_device = ppb_var_var_to_utf8(longname, NULL); vc->fd = v4l2_open(capture_device, O_RDWR); ppb_var_release(longname); if (vc->fd < 0) { result = PP_ERROR_NOACCESS; goto point_1; } struct v4l2_capability caps; if (v4l2_ioctl(vc->fd, VIDIOC_QUERYCAP, &caps) != 0) { result = PP_ERROR_FAILED; goto point_2; } #ifdef V4L2_CAP_DEVICE_CAPS const uint32_t device_caps = (caps.capabilities & V4L2_CAP_DEVICE_CAPS) ? caps.device_caps : caps.capabilities; #else const uint32_t device_caps = caps.capabilities; #endif // V4L2_CAP_DEVICE_CAPS if (!(device_caps & V4L2_CAP_VIDEO_CAPTURE)) { trace_error("%s, device can't capture\n", __func__); result = PP_ERROR_FAILED; goto point_2; } if (!(device_caps & V4L2_CAP_READWRITE)) { trace_error("%s, device doesn't support read/write interface\n", __func__); result = PP_ERROR_FAILED; goto point_2; } if (requested_info) { vc->width = requested_info->width; vc->height = requested_info->height; vc->fps = requested_info->frames_per_second; } else { vc->width = 640; vc->height = 480; vc->fps = 15; } struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt.pix.width = vc->width, .fmt.pix.height = vc->height, .fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420, // PPAPI hardcodes format to YUV420 .fmt.pix.field = V4L2_FIELD_INTERLACED, }; if (v4l2_ioctl(vc->fd, VIDIOC_S_FMT, &fmt) != 0) { trace_error("%s, failed to set resolution\n", __func__); result = PP_ERROR_FAILED; goto point_2; } vc->width = fmt.fmt.pix.width; vc->height = fmt.fmt.pix.height; vc->buffer_size = fmt.fmt.pix.sizeimage; // buffer size in bytes vc->buffer_count = MAX(buffer_count, 5); // limit lowest number of buffers, just in case vc->buffers = calloc(sizeof(*vc->buffers), vc->buffer_count); if (!vc->buffers) { trace_error("%s, memory allocation failure (1)\n", __func__); result = PP_ERROR_FAILED; goto point_2; } vc->buffer_is_free = malloc(sizeof(*vc->buffer_is_free) * vc->buffer_count); if (!vc->buffer_is_free) { trace_error("%s, memory allocation failure (2)\n", __func__); result = PP_ERROR_FAILED; goto point_3; } for (unsigned int k = 0; k < vc->buffer_count; k ++) { vc->buffer_is_free[k] = 1; vc->buffers[k] = ppb_buffer_create(vc->instance->id, vc->buffer_size); if (vc->buffers[k] == 0) goto point_4; } struct PP_VideoCaptureDeviceInfo_Dev info = { .width = vc->width, .height = vc->height, .frames_per_second = vc->fps, }; vc->ppp_video_capture_dev->OnDeviceInfo(vc->instance->id, video_capture, &info, vc->buffer_count, vc->buffers); result = PP_OK; goto point_1; point_4: for (unsigned int k = 0; k < vc->buffer_count; k ++) ppb_core_release_resource(vc->buffers[k]); free_and_nullify(vc->buffer_is_free); point_3: free_and_nullify(vc->buffers); point_2: v4l2_close(vc->fd); vc->fd = -1; point_1: pp_resource_release(video_capture); ppb_core_call_on_main_thread2(0, callback, result, __func__); return PP_OK_COMPLETIONPENDING; } struct on_buffer_ready_param_s { PP_Instance instance; PP_Resource video_capture; uint32_t buf_idx; const struct PPP_VideoCapture_Dev_0_1 *ppp_video_capture_dev; }; static void on_buffer_ready_comt(void *user_data, int32_t result) { struct on_buffer_ready_param_s *p = user_data; struct pp_instance_s *pp_i = tables_get_pp_instance(p->instance); if (!pp_i) return; p->ppp_video_capture_dev->OnBufferReady(p->instance, p->video_capture, p->buf_idx); g_slice_free1(sizeof(*p), p); } static void * video_capture_thread(void *param) { struct pp_video_capture_s *vc = param; PP_Resource video_capture = vc->self_id; PP_Instance instance = vc->instance->id; const int fd = vc->fd; const size_t buffer_size = vc->buffer_size; vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) goto gone; while (!vc->terminate_thread) { // find free buffer uint32_t buf_idx = (uint32_t)-1; for (uint32_t k = 0; k < vc->buffer_count; k ++) { if (vc->buffer_is_free[k]) { buf_idx = k; vc->buffer_is_free[k] = 0; break; } } if (buf_idx == (uint32_t)-1) { // all buffers are busy, wait for some to free, with resource unlocked pp_resource_release(video_capture); usleep(10); vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) goto gone; continue; } PP_Resource buffer = vc->buffers[buf_idx]; pp_resource_release(video_capture); // wait on v4l2_read() with resource unlocked void *ptr = ppb_buffer_map(buffer); RETRY_ON_EINTR(v4l2_read(fd, ptr, buffer_size)); ppb_buffer_unmap(buffer); vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) goto gone; struct on_buffer_ready_param_s *p = g_slice_alloc(sizeof(*p)); p->instance = instance; p->video_capture = video_capture; p->buf_idx = buf_idx; p->ppp_video_capture_dev = vc->ppp_video_capture_dev; ppb_core_call_on_main_thread2(0, PP_MakeCCB(on_buffer_ready_comt, p), PP_OK, __func__); } pp_resource_release(video_capture); return NULL; gone: trace_error("%s, resource gone\n", __func__); return NULL; } int32_t ppb_video_capture_start_capture(PP_Resource video_capture) { struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (vc->thread_started) goto done; if (vc->fd < 0) { trace_error("%s, device is closed\n", __func__); pp_resource_release(video_capture); return PP_ERROR_FAILED; } vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STARTING); pp_resource_ref(video_capture); // prevents freeing while thread is still running pthread_create(&vc->thread, NULL, video_capture_thread, vc); vc->thread_started = 1; vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STARTED); done: pp_resource_release(video_capture); return PP_OK; } int32_t ppb_video_capture_reuse_buffer(PP_Resource video_capture, uint32_t buffer) { struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (buffer < vc->buffer_count) vc->buffer_is_free[buffer] = 1; pp_resource_release(video_capture); return PP_OK; } int32_t ppb_video_capture_stop_capture(PP_Resource video_capture) { struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (!vc->thread_started) goto done; vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STOPPING); vc->terminate_thread = 1; pthread_t thread = vc->thread; pp_resource_release(video_capture); pthread_join(thread, NULL); vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, resource gone\n", __func__); return PP_ERROR_BADRESOURCE; } vc->thread_started = 0; vc->terminate_thread = 0; vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STOPPED); pp_resource_unref(video_capture); // remove reference made in start_capture() done: pp_resource_release(video_capture); return PP_OK; } void ppb_video_capture_close(PP_Resource video_capture) { ppb_video_capture_stop_capture(video_capture); struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return; } ppb_video_capture_destroy(vc); pp_resource_release(video_capture); return; } // trace wrappers TRACE_WRAPPER PP_Resource trace_ppb_video_capture_create(PP_Instance instance) { trace_info("[PPB] {full} %s instance=%d\n", __func__+6, instance); return ppb_video_capture_create(instance); }