static int hc_image(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; pixmap_t *pm; char errbuf[200]; const char *content; image_meta_t im = {0}; im.im_no_decoding = 1; rstr_t *url = rstr_alloc(remain); pm = backend_imageloader(url, &im, NULL, errbuf, sizeof(errbuf), NULL, NULL, NULL); rstr_release(url); if(pm == NULL) return http_error(hc, 404, "Unable to load image %s : %s", remain, errbuf); if(!pixmap_is_coded(pm)) { pixmap_release(pm); return http_error(hc, 404, "Unable to load image %s : Original data not available", remain); } htsbuf_queue_init(&out, 0); htsbuf_append(&out, pm->pm_data, pm->pm_size); switch(pm->pm_type) { case PIXMAP_JPEG: content = "image/jpeg"; break; case PIXMAP_PNG: content = "image/png"; break; case PIXMAP_GIF: content = "image/gif"; break; default: content = "image"; break; } pixmap_release(pm); return http_send_reply(hc, 0, content, NULL, NULL, 0, &out); }
void jpeg_info_clear(jpeginfo_t *ji) { if(ji->ji_thumbnail != NULL) pixmap_release(ji->ji_thumbnail); rstr_release(ji->ji_manufacturer); rstr_release(ji->ji_equipment); }
/** * Free resources created by glw_tex_backend_decode() */ void glw_tex_backend_free_loader_resources(glw_loadable_texture_t *glt) { if(glt->glt_pixmap != NULL) { pixmap_release(glt->glt_pixmap); glt->glt_pixmap = NULL; } }
void video_overlay_destroy(video_overlay_t *vo) { if(vo->vo_pixmap != NULL) pixmap_release(vo->vo_pixmap); free(vo->vo_text); free(vo); }
void video_overlay_destroy(video_decoder_t *vd, video_overlay_t *vo) { TAILQ_REMOVE(&vd->vd_overlay_queue, vo, vo_link); if(vo->vo_pixmap != NULL) pixmap_release(vo->vo_pixmap); free(vo->vo_text); free(vo); }
int glw_tex_backend_load(glw_root_t *gr, glw_loadable_texture_t *glt, pixmap_t *pm) { int size; switch(pm->pm_type) { default: return 0; case PIXMAP_RGB24: glt->glt_format = GL_RGB; size = pm->pm_width * pm->pm_height * 4; break; case PIXMAP_BGR32: glt->glt_format = GL_RGBA; size = pm->pm_width * pm->pm_height * 4; break; case PIXMAP_IA: glt->glt_format = GL_LUMINANCE_ALPHA; size = pm->pm_width * pm->pm_height * 2; break; case PIXMAP_I: glt->glt_format = GL_LUMINANCE; size = pm->pm_width * pm->pm_height; break; } if(glt->glt_pixmap != NULL) pixmap_release(glt->glt_pixmap); glt->glt_pixmap = pixmap_dup(pm); return size; }
static void glw_text_bitmap_dtor(glw_t *w) { glw_text_bitmap_t *gtb = (void *)w; glw_root_t *gr = w->glw_root; free(gtb->gtb_caption); free(gtb->gtb_uc_buffer); rstr_release(gtb->gtb_font); if(gtb->gtb_pixmap != NULL) pixmap_release(gtb->gtb_pixmap); LIST_REMOVE(gtb, gtb_global_link); glw_tex_destroy(w->glw_root, >b->gtb_texture); glw_renderer_free(>b->gtb_text_renderer); glw_renderer_free(>b->gtb_cursor_renderer); switch(gtb->gtb_state) { case GTB_IDLE: case GTB_DIMENSIONING: case GTB_NEED_RENDER: case GTB_RENDERING: case GTB_VALID: break; case GTB_QUEUED_FOR_DIMENSIONING: TAILQ_REMOVE(&gr->gr_gtb_dim_queue, gtb, gtb_workq_link); break; case GTB_QUEUED_FOR_RENDERING: TAILQ_REMOVE(&gr->gr_gtb_render_queue, gtb, gtb_workq_link); break; } }
static pixmap_t * rpi_pixmap_decode(pixmap_t *pm, const image_meta_t *im, char *errbuf, size_t errlen) { if(pm->pm_type != PIXMAP_JPEG) return NULL; #ifdef TIMING int64_t ts = showtime_get_ts(), ts2; #endif rpi_pixmap_decoder_t *rpd = pixmap_decoder_create(OMX_IMAGE_CodingJPEG); if(rpd == NULL) return NULL; rpd->rpd_im = im; #ifdef NOCOPY #error check rpd->rpd_decoder->oc_stream_corrupt OMX_PARAM_PORTDEFINITIONTYPE portdef; memset(&portdef, 0, sizeof(portdef)); portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); portdef.nVersion.nVersion = OMX_VERSION; portdef.nPortIndex = rpd->rpd_decoder->oc_inport; omxchk(OMX_GetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omx_send_command(rpd->rpd_decoder, OMX_CommandPortEnable, rpd->rpd_decoder->oc_inport, NULL, 0); OMX_BUFFERHEADERTYPE *buf; for(int i = 0; i < portdef.nBufferCountActual; i++) { omxchk(OMX_UseBuffer(rpd->rpd_decoder->oc_handle, &buf, rpd->rpd_decoder->oc_inport, NULL, pm->pm_size, pm->pm_data)); } // Waits for the OMX_CommandPortEnable command omx_wait_command(rpd->rpd_decoder); omx_set_state(rpd->rpd_decoder, OMX_StateExecuting); CHECKPOINT("Initialized"); buf->nOffset = 0; buf->nFilledLen = pm->pm_size; buf->nFlags |= OMX_BUFFERFLAG_EOS; rpd->rpd_decoder->oc_inflight_buffers++; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); while(rpd->rpd_change == 0) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); CHECKPOINT("Setup tunnel"); setup_tunnel(rpd); #else const void *data = pm->pm_data; size_t len = pm->pm_size; hts_mutex_lock(&rpd->rpd_mtx); while(len > 0) { OMX_BUFFERHEADERTYPE *buf; if(rpd->rpd_decoder->oc_stream_corrupt) break; if(rpd->rpd_change == 1) { rpd->rpd_change = 2; hts_mutex_unlock(&rpd->rpd_mtx); setup_tunnel(rpd); hts_mutex_lock(&rpd->rpd_mtx); continue; } if(rpd->rpd_decoder->oc_avail == NULL) { hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); continue; } buf = rpd->rpd_decoder->oc_avail; rpd->rpd_decoder->oc_avail = buf->pAppPrivate; rpd->rpd_decoder->oc_inflight_buffers++; hts_mutex_unlock(&rpd->rpd_mtx); buf->nOffset = 0; buf->nFilledLen = MIN(len, buf->nAllocLen); memcpy(buf->pBuffer, data, buf->nFilledLen); buf->nFlags = 0; if(len <= buf->nAllocLen) buf->nFlags |= OMX_BUFFERFLAG_EOS; data += buf->nFilledLen; len -= buf->nFilledLen; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); } if(rpd->rpd_decoder->oc_stream_corrupt) { hts_mutex_unlock(&rpd->rpd_mtx); goto err; } if(rpd->rpd_change != 2) { while(rpd->rpd_change == 0 && !rpd->rpd_decoder->oc_stream_corrupt) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); if(rpd->rpd_decoder->oc_stream_corrupt) goto err; setup_tunnel(rpd); } else { hts_mutex_unlock(&rpd->rpd_mtx); } #endif omx_wait_fill_buffer(rpd->rpd_resizer, rpd->rpd_buf); CHECKPOINT("Got buffer"); err: omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_outport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_inport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_outport); if(rpd->rpd_tunnel != NULL) { omx_tunnel_destroy(rpd->rpd_tunnel); rpd->rpd_tunnel = NULL; } omx_set_state(rpd->rpd_decoder, OMX_StateIdle); omx_set_state(rpd->rpd_resizer, OMX_StateIdle); if(rpd->rpd_buf != NULL) { omxchk(OMX_FreeBuffer(rpd->rpd_resizer->oc_handle, rpd->rpd_resizer->oc_outport, rpd->rpd_buf)); } omx_release_buffers(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_set_state(rpd->rpd_resizer, OMX_StateLoaded); omx_set_state(rpd->rpd_decoder, OMX_StateLoaded); omx_component_destroy(rpd->rpd_resizer); omx_component_destroy(rpd->rpd_decoder); hts_cond_destroy(&rpd->rpd_cond); hts_mutex_destroy(&rpd->rpd_mtx); pixmap_t *out = rpd->rpd_pm; if(out) { pixmap_release(pm); } else { snprintf(errbuf, errlen, "Load error"); } free(rpd); CHECKPOINT("All done"); return out; }
static pixmap_t * fa_image_from_video2(const char *url, const image_meta_t *im, const char *cacheid, char *errbuf, size_t errlen, int sec, time_t mtime, cancellable_t *c) { pixmap_t *pm = NULL; if(ifv_url == NULL || strcmp(url, ifv_url)) { // Need to open int i; AVFormatContext *fctx; fa_handle_t *fh = fa_open_ex(url, errbuf, errlen, FA_BUFFERED_BIG, NULL); if(fh == NULL) return NULL; AVIOContext *avio = fa_libav_reopen(fh, 0); if((fctx = fa_libav_open_format(avio, url, NULL, 0, NULL, 0, 0, 0)) == NULL) { fa_libav_close(avio); snprintf(errbuf, errlen, "Unable to open format"); return NULL; } if(!strcmp(fctx->iformat->name, "avi")) fctx->flags |= AVFMT_FLAG_GENPTS; AVCodecContext *ctx = NULL; for(i = 0; i < fctx->nb_streams; i++) { if(fctx->streams[i]->codec != NULL && fctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { ctx = fctx->streams[i]->codec; break; } } if(ctx == NULL) { fa_libav_close_format(fctx); return NULL; } AVCodec *codec = avcodec_find_decoder(ctx->codec_id); if(codec == NULL) { fa_libav_close_format(fctx); snprintf(errbuf, errlen, "Unable to find codec"); return NULL; } if(avcodec_open2(ctx, codec, NULL) < 0) { fa_libav_close_format(fctx); snprintf(errbuf, errlen, "Unable to open codec"); return NULL; } ifv_close(); ifv_stream = i; ifv_url = strdup(url); ifv_fctx = fctx; ifv_ctx = ctx; } AVPacket pkt; AVFrame *frame = av_frame_alloc(); int got_pic; AVStream *st = ifv_fctx->streams[ifv_stream]; int64_t ts = av_rescale(sec, st->time_base.den, st->time_base.num); if(av_seek_frame(ifv_fctx, ifv_stream, ts, AVSEEK_FLAG_BACKWARD) < 0) { ifv_close(); snprintf(errbuf, errlen, "Unable to seek to %"PRId64, ts); return NULL; } avcodec_flush_buffers(ifv_ctx); #define MAX_FRAME_SCAN 500 int cnt = MAX_FRAME_SCAN; while(1) { int r; r = av_read_frame(ifv_fctx, &pkt); if(r == AVERROR(EAGAIN)) continue; if(r == AVERROR_EOF) break; if(cancellable_is_cancelled(c)) { snprintf(errbuf, errlen, "Cancelled"); av_free_packet(&pkt); break; } if(r != 0) { ifv_close(); break; } if(pkt.stream_index != ifv_stream) { av_free_packet(&pkt); continue; } cnt--; int want_pic = pkt.pts >= ts || cnt <= 0; ifv_ctx->skip_frame = want_pic ? AVDISCARD_DEFAULT : AVDISCARD_NONREF; avcodec_decode_video2(ifv_ctx, frame, &got_pic, &pkt); av_free_packet(&pkt); if(got_pic == 0 || !want_pic) { continue; } int w,h; if(im->im_req_width != -1 && im->im_req_height != -1) { w = im->im_req_width; h = im->im_req_height; } else if(im->im_req_width != -1) { w = im->im_req_width; h = im->im_req_width * ifv_ctx->height / ifv_ctx->width; } else if(im->im_req_height != -1) { w = im->im_req_height * ifv_ctx->width / ifv_ctx->height; h = im->im_req_height; } else { w = im->im_req_width; h = im->im_req_height; } pm = pixmap_create(w, h, PIXMAP_BGR32, 0); if(pm == NULL) { ifv_close(); snprintf(errbuf, errlen, "Out of memory"); av_free(frame); return NULL; } struct SwsContext *sws; sws = sws_getContext(ifv_ctx->width, ifv_ctx->height, ifv_ctx->pix_fmt, w, h, AV_PIX_FMT_BGR32, SWS_BILINEAR, NULL, NULL, NULL); if(sws == NULL) { ifv_close(); snprintf(errbuf, errlen, "Scaling failed"); pixmap_release(pm); av_free(frame); return NULL; } uint8_t *ptr[4] = {0,0,0,0}; int strides[4] = {0,0,0,0}; ptr[0] = pm->pm_pixels; strides[0] = pm->pm_linesize; sws_scale(sws, (const uint8_t **)frame->data, frame->linesize, 0, ifv_ctx->height, ptr, strides); sws_freeContext(sws); write_thumb(ifv_ctx, frame, w, h, cacheid, mtime); break; } av_frame_free(&frame); if(pm == NULL) snprintf(errbuf, errlen, "Frame not found (scanned %d)", MAX_FRAME_SCAN - cnt); avcodec_flush_buffers(ifv_ctx); callout_arm(&thumb_flush_callout, ifv_autoclose, NULL, 5); return pm; }
pixmap_t * fa_imageloader(const char *url, const struct image_meta *im, const char **vpaths, char *errbuf, size_t errlen, int *cache_control, cancellable_t *c) { uint8_t p[16]; int r; int width = -1, height = -1, orientation = 0; fa_handle_t *fh; pixmap_t *pm; pixmap_type_t fmt; #if ENABLE_LIBAV if(strchr(url, '#')) return fa_image_from_video(url, im, errbuf, errlen, cache_control, c); #endif if(!im->im_want_thumb) return fa_imageloader2(url, vpaths, errbuf, errlen, cache_control, c); fa_open_extra_t foe = { .foe_c = c }; if((fh = fa_open_vpaths(url, vpaths, errbuf, errlen, FA_BUFFERED_SMALL, &foe)) == NULL) return NULL; if(ONLY_CACHED(cache_control)) { snprintf(errbuf, errlen, "Not cached"); return NULL; } if(fa_read(fh, p, sizeof(p)) != sizeof(p)) { snprintf(errbuf, errlen, "File too short"); fa_close(fh); return NULL; } /* Probe format */ if((p[6] == 'J' && p[7] == 'F' && p[8] == 'I' && p[9] == 'F') || (p[6] == 'E' && p[7] == 'x' && p[8] == 'i' && p[9] == 'f')) { jpeginfo_t ji; if(jpeg_info(&ji, jpeginfo_reader, fh, JPEG_INFO_DIMENSIONS | JPEG_INFO_ORIENTATION | (im->im_want_thumb ? JPEG_INFO_THUMBNAIL : 0), p, sizeof(p), errbuf, errlen)) { fa_close(fh); return NULL; } if(im->im_want_thumb && ji.ji_thumbnail) { pixmap_t *pm = pixmap_dup(ji.ji_thumbnail); fa_close(fh); jpeg_info_clear(&ji); return pm; } fmt = PIXMAP_JPEG; width = ji.ji_width; height = ji.ji_height; orientation = ji.ji_orientation; jpeg_info_clear(&ji); } else if(!memcmp(pngsig, p, 8)) { fmt = PIXMAP_PNG; } else if(!memcmp(gif87sig, p, sizeof(gif87sig)) || !memcmp(gif89sig, p, sizeof(gif89sig))) { fmt = PIXMAP_GIF; } else if(!memcmp(svgsig1, p, sizeof(svgsig1)) || !memcmp(svgsig2, p, sizeof(svgsig2))) { fmt = PIXMAP_SVG; } else { snprintf(errbuf, errlen, "Unknown format"); fa_close(fh); return NULL; } int64_t s = fa_fsize(fh); if(s < 0) { snprintf(errbuf, errlen, "Can't read from non-seekable file"); fa_close(fh); return NULL; } pm = pixmap_alloc_coded(NULL, s, fmt); if(pm == NULL) { snprintf(errbuf, errlen, "Out of memory"); fa_close(fh); return NULL; } pm->pm_width = width; pm->pm_height = height; pm->pm_orientation = orientation; fa_seek(fh, SEEK_SET, 0); r = fa_read(fh, pm->pm_data, pm->pm_size); fa_close(fh); if(r != pm->pm_size) { pixmap_release(pm); snprintf(errbuf, errlen, "Read error"); return NULL; } return pm; }
static void screenshot_process(void *task) { pixmap_t *pm = task; if(pm == NULL) { screenshot_response(NULL, "Screenshot not supported on this platform"); return; } TRACE(TRACE_DEBUG, "Screenshot", "Processing image %d x %d", pm->pm_width, pm->pm_height); int codecid = AV_CODEC_ID_PNG; if(screenshot_connection) codecid = AV_CODEC_ID_MJPEG; buf_t *b = screenshot_compress(pm, codecid); pixmap_release(pm); if(b == NULL) { screenshot_response(NULL, "Unable to compress image"); return; } if(!screenshot_connection) { char path[512]; char errbuf[512]; snprintf(path, sizeof(path), "%s/screenshot.png", gconf.cache_path); fa_handle_t *fa = fa_open_ex(path, errbuf, sizeof(errbuf), FA_WRITE, NULL); if(fa == NULL) { TRACE(TRACE_ERROR, "SCREENSHOT", "Unable to open %s -- %s", path, errbuf); buf_release(b); return; } fa_write(fa, buf_data(b), buf_len(b)); fa_close(fa); TRACE(TRACE_INFO, "SCREENSHOT", "Written to %s", path); buf_release(b); return; } buf_t *result = NULL; htsbuf_queue_t hq; htsbuf_queue_init(&hq, 0); htsbuf_append(&hq, "image=", 6); htsbuf_append_and_escape_url_len(&hq, buf_cstr(b), buf_len(b)); char errbuf[256]; int ret = http_req("https://api.imgur.com/3/upload", HTTP_FLAGS(FA_CONTENT_ON_ERROR), HTTP_REQUEST_HEADER("Authorization", "Client-ID 7c79b311d4797ed"), HTTP_RESULT_PTR(&result), HTTP_POSTDATA(&hq, "application/x-www-form-urlencoded"), HTTP_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(ret) { screenshot_response(NULL, errbuf); } else { htsmsg_t *response = htsmsg_json_deserialize(buf_cstr(result)); if(response == NULL) { screenshot_response(NULL, "Unable to parse imgur response"); } else { if(htsmsg_get_u32_or_default(response, "success", 0)) { const char *url = htsmsg_get_str_multi(response, "data", "link", NULL); screenshot_response(url, "No link in imgur response"); } else { const char *msg = htsmsg_get_str_multi(response, "data", "error", NULL); if(msg == NULL) { screenshot_response(NULL, "Unkown imgur error"); } else { snprintf(errbuf, sizeof(errbuf), "Imgur error: %s", msg); screenshot_response(NULL, errbuf); } } htsmsg_release(response); } buf_release(result); } buf_release(b); }
/** * Free a token. * It must be delinked for all lists before */ void glw_view_token_free(token_t *t) { int i; #ifdef GLW_VIEW_ERRORINFO rstr_release(t->file); #endif switch(t->type) { case TOKEN_FUNCTION: if(t->t_func->ctor != NULL) t->t_func->dtor(t); break; case TOKEN_PROPERTY_REF: prop_ref_dec(t->t_prop); break; case TOKEN_PROPERTY_OWNER: prop_destroy(t->t_prop); break; case TOKEN_FLOAT: case TOKEN_INT: case TOKEN_VECTOR_FLOAT: case TOKEN_VECTOR_INT: case TOKEN_OBJECT_ATTRIBUTE: case TOKEN_PROPERTY_SUBSCRIPTION: case TOKEN_VOID: case TOKEN_DIRECTORY: case TOKEN_CSTRING: break; case TOKEN_VECTOR_STRING: for(i = 0; i < t->t_elements; i++) free(t->t_string_vector[i]); break; case TOKEN_START: case TOKEN_END: case TOKEN_HASH: case TOKEN_ASSIGNMENT: case TOKEN_COND_ASSIGNMENT: case TOKEN_END_OF_EXPR: case TOKEN_SEPARATOR: case TOKEN_BLOCK_OPEN: case TOKEN_BLOCK_CLOSE: case TOKEN_LEFT_PARENTHESIS: case TOKEN_RIGHT_PARENTHESIS: case TOKEN_LEFT_BRACKET: case TOKEN_RIGHT_BRACKET: case TOKEN_DOT: case TOKEN_ADD: case TOKEN_SUB: case TOKEN_MULTIPLY: case TOKEN_DIVIDE: case TOKEN_MODULO: case TOKEN_DOLLAR: case TOKEN_AMPERSAND: case TOKEN_BOOLEAN_AND: case TOKEN_BOOLEAN_OR: case TOKEN_BOOLEAN_XOR: case TOKEN_BOOLEAN_NOT: case TOKEN_EQ: case TOKEN_NEQ: case TOKEN_NULL_COALESCE: case TOKEN_LT: case TOKEN_GT: case TOKEN_EXPR: case TOKEN_RPN: case TOKEN_BLOCK: case TOKEN_NOP: break; case TOKEN_RSTRING: case TOKEN_IDENTIFIER: case TOKEN_PROPERTY_VALUE_NAME: case TOKEN_PROPERTY_CANONICAL_NAME: rstr_release(t->t_rstring); break; case TOKEN_PIXMAP: pixmap_release(t->t_pixmap); break; case TOKEN_EVENT: t->t_gem->gem_dtor(t->t_gem); break; case TOKEN_LINK: rstr_release(t->t_link_rtitle); rstr_release(t->t_link_rurl); break; case TOKEN_num: abort(); } free(t); }
static void sunxi_set_bg(const char *path) { char errbuf[128]; image_meta_t im = {0}; unsigned long args[4] = {0}; pixmap_t *pm; int width = 1280, height = 720; int r; return; // hum im.im_req_width = width; im.im_req_height = height; rstr_t *rpath = rstr_alloc(path); pm = backend_imageloader(rpath, &im, NULL, errbuf, sizeof(errbuf), NULL, NULL, NULL); rstr_release(rpath); if(pm == NULL) { TRACE(TRACE_ERROR, "BG", "Unable to load %s -- %s", path, errbuf); return; } int bpp; switch(pm->pm_type) { case PIXMAP_RGB24: bpp = 3; break; case PIXMAP_BGR32: bpp = 4; break; default: abort(); } size_t tsize = pm->pm_height * pm->pm_linesize; hts_mutex_lock(&sunxi.gfxmem_mutex); uint8_t *dst = tlsf_memalign(sunxi.gfxmem, 1024, tsize); hts_mutex_unlock(&sunxi.gfxmem_mutex); memcpy(dst, pm->pm_pixels, tsize); pixmap_release(pm); __disp_video_fb_t frmbuf; memset(&frmbuf, 0, sizeof(__disp_video_fb_t)); frmbuf.addr[0] = va_to_pa(dst); frmbuf.addr[1] = va_to_pa(dst); frmbuf.addr[2] = va_to_pa(dst); args[1] = DISP_LAYER_WORK_MODE_NORMAL; int hlay = ioctl(sunxi.dispfd, DISP_CMD_LAYER_REQUEST, args); if(hlay == -1) exit(3); __disp_layer_info_t l; memset(&l, 0, sizeof(l)); l.mode = DISP_LAYER_WORK_MODE_NORMAL; l.pipe = 1; l.fb.size.width = pm->pm_linesize / bpp; l.fb.size.height = pm->pm_height; l.fb.addr[0] = frmbuf.addr[0]; l.fb.addr[1] = frmbuf.addr[1]; l.fb.addr[2] = frmbuf.addr[2]; switch(pm->pm_type) { case PIXMAP_RGB24: l.fb.format = DISP_FORMAT_RGB888; l.fb.br_swap = 1; l.fb.mode = DISP_MOD_INTERLEAVED; break; case PIXMAP_BGR32: l.fb.format = DISP_FORMAT_ARGB8888; l.fb.br_swap = 1; l.fb.mode = DISP_MOD_INTERLEAVED; break; default: abort(); } /// l.fb.seq = 0; // l.fb.mode = DISP_MOD_NON_MB_PLANAR; // l.fb.format = DISP_FORMAT_YUV420; l.ck_enable = 0; l.alpha_en = 1; l.alpha_val = 0; l.src_win.x = 0; l.src_win.y = 0; l.src_win.width = width; l.src_win.height = height; l.scn_win.x = 0; l.scn_win.y = 0; l.scn_win.width = width; l.scn_win.height = height; args[1] = hlay; args[2] = (__u32)&l; args[3] = 0; r = ioctl(sunxi.dispfd,DISP_CMD_LAYER_SET_PARA,(void*)args); if(r) perror("ioctl(disphd,DISP_CMD_LAYER_SET_PARA)"); args[1] = hlay; args[2] = 0; r = ioctl(sunxi.dispfd,DISP_CMD_LAYER_OPEN,(void*)args); if(r) perror("ioctl(disphd,DISP_CMD_LAYER_OPEN)"); bg_open = 1; args[1] = hlay; if(ioctl(sunxi.dispfd, DISP_CMD_LAYER_BOTTOM, args)) perror("ioctl(disphd,DISP_CMD_LAYER_BOTTOM)"); bg_layer = hlay; }
static image_t * fa_image_from_video2(const char *url, const image_meta_t *im, const char *cacheid, char *errbuf, size_t errlen, int sec, time_t mtime, cancellable_t *c) { image_t *img = NULL; if(ifv_url == NULL || strcmp(url, ifv_url)) { // Need to open int i; AVFormatContext *fctx; fa_handle_t *fh = fa_open_ex(url, errbuf, errlen, FA_BUFFERED_BIG, NULL); if(fh == NULL) return NULL; AVIOContext *avio = fa_libav_reopen(fh, 0); if((fctx = fa_libav_open_format(avio, url, NULL, 0, NULL, 0, 0, 0)) == NULL) { fa_libav_close(avio); snprintf(errbuf, errlen, "Unable to open format"); return NULL; } if(!strcmp(fctx->iformat->name, "avi")) fctx->flags |= AVFMT_FLAG_GENPTS; AVCodecContext *ctx = NULL; int vstream = 0; for(i = 0; i < fctx->nb_streams; i++) { AVStream *st = fctx->streams[i]; AVCodecContext *c = st->codec; AVDictionaryEntry *mt; if(c == NULL) continue; switch(c->codec_type) { case AVMEDIA_TYPE_VIDEO: if(ctx == NULL) { vstream = i; ctx = fctx->streams[i]->codec; } break; case AVMEDIA_TYPE_ATTACHMENT: mt = av_dict_get(st->metadata, "mimetype", NULL, AV_DICT_IGNORE_SUFFIX); if(sec == -1 && mt != NULL && (!strcmp(mt->value, "image/jpeg") || !strcmp(mt->value, "image/png"))) { int64_t offset = st->attached_offset; int size = st->attached_size; fa_libav_close_format(fctx); return thumb_from_attachment(url, offset, size, errbuf, errlen, cacheid, mtime); } break; default: break; } } if(ctx == NULL) { fa_libav_close_format(fctx); return NULL; } AVCodec *codec = avcodec_find_decoder(ctx->codec_id); if(codec == NULL) { fa_libav_close_format(fctx); snprintf(errbuf, errlen, "Unable to find codec"); return NULL; } if(avcodec_open2(ctx, codec, NULL) < 0) { fa_libav_close_format(fctx); snprintf(errbuf, errlen, "Unable to open codec"); return NULL; } ifv_close(); ifv_stream = vstream; ifv_url = strdup(url); ifv_fctx = fctx; ifv_ctx = ctx; } AVPacket pkt; AVFrame *frame = av_frame_alloc(); int got_pic; #define MAX_FRAME_SCAN 500 int cnt = MAX_FRAME_SCAN; AVStream *st = ifv_fctx->streams[ifv_stream]; if(sec == -1) { // Automatically try to find a good frame int duration_in_seconds = ifv_fctx->duration / 1000000; sec = MAX(1, duration_in_seconds * 0.05); // 5% of duration sec = MIN(sec, 150); // , buy no longer than 2:30 in sec = MAX(0, MIN(sec, duration_in_seconds - 1)); cnt = 1; } int64_t ts = av_rescale(sec, st->time_base.den, st->time_base.num); int delayed_seek = 0; if(ifv_ctx->codec_id == AV_CODEC_ID_RV40 || ifv_ctx->codec_id == AV_CODEC_ID_RV30) { // Must decode one frame delayed_seek = 1; } else { if(av_seek_frame(ifv_fctx, ifv_stream, ts, AVSEEK_FLAG_BACKWARD) < 0) { ifv_close(); snprintf(errbuf, errlen, "Unable to seek to %"PRId64, ts); return NULL; } } avcodec_flush_buffers(ifv_ctx); while(1) { int r; r = av_read_frame(ifv_fctx, &pkt); if(r == AVERROR(EAGAIN)) continue; if(r == AVERROR_EOF) break; if(cancellable_is_cancelled(c)) { snprintf(errbuf, errlen, "Cancelled"); av_free_packet(&pkt); break; } if(r != 0) { ifv_close(); break; } if(pkt.stream_index != ifv_stream) { av_free_packet(&pkt); continue; } cnt--; int want_pic = pkt.pts >= ts || cnt <= 0; ifv_ctx->skip_frame = want_pic ? AVDISCARD_DEFAULT : AVDISCARD_NONREF; avcodec_decode_video2(ifv_ctx, frame, &got_pic, &pkt); av_free_packet(&pkt); if(delayed_seek) { delayed_seek = 0; if(av_seek_frame(ifv_fctx, ifv_stream, ts, AVSEEK_FLAG_BACKWARD) < 0) { ifv_close(); break; } continue; } if(got_pic == 0 || !want_pic) { continue; } int w,h; if(im->im_req_width != -1 && im->im_req_height != -1) { w = im->im_req_width; h = im->im_req_height; } else if(im->im_req_width != -1) { w = im->im_req_width; h = im->im_req_width * ifv_ctx->height / ifv_ctx->width; } else if(im->im_req_height != -1) { w = im->im_req_height * ifv_ctx->width / ifv_ctx->height; h = im->im_req_height; } else { w = im->im_req_width; h = im->im_req_height; } pixmap_t *pm = pixmap_create(w, h, PIXMAP_BGR32, 0); if(pm == NULL) { ifv_close(); snprintf(errbuf, errlen, "Out of memory"); av_free(frame); return NULL; } struct SwsContext *sws; sws = sws_getContext(ifv_ctx->width, ifv_ctx->height, ifv_ctx->pix_fmt, w, h, AV_PIX_FMT_BGR32, SWS_BILINEAR, NULL, NULL, NULL); if(sws == NULL) { ifv_close(); snprintf(errbuf, errlen, "Scaling failed"); pixmap_release(pm); av_free(frame); return NULL; } uint8_t *ptr[4] = {0,0,0,0}; int strides[4] = {0,0,0,0}; ptr[0] = pm->pm_data; strides[0] = pm->pm_linesize; sws_scale(sws, (const uint8_t **)frame->data, frame->linesize, 0, ifv_ctx->height, ptr, strides); sws_freeContext(sws); write_thumb(ifv_ctx, frame, w, h, cacheid, mtime); img = image_create_from_pixmap(pm); pixmap_release(pm); break; } av_frame_free(&frame); if(img == NULL) snprintf(errbuf, errlen, "Frame not found (scanned %d)", MAX_FRAME_SCAN - cnt); if(ifv_ctx != NULL) { avcodec_flush_buffers(ifv_ctx); callout_arm(&thumb_flush_callout, ifv_autoclose, NULL, 5); } return img; }
static pixmap_t * fa_image_from_video2(const char *url, const image_meta_t *im, const char *cacheid, char *errbuf, size_t errlen, int sec, time_t mtime, fa_load_cb_t *cb, void *opaque) { pixmap_t *pm = NULL; if(ifv_url == NULL || strcmp(url, ifv_url)) { // Need to open int i; AVFormatContext *fctx; fa_handle_t *fh = fa_open_ex(url, errbuf, errlen, FA_BUFFERED_BIG, NULL); if(fh == NULL) return NULL; AVIOContext *avio = fa_libav_reopen(fh); if((fctx = fa_libav_open_format(avio, url, NULL, 0, NULL)) == NULL) { fa_libav_close(avio); snprintf(errbuf, errlen, "Unable to open format"); return NULL; } if(!strcmp(fctx->iformat->name, "avi")) fctx->flags |= AVFMT_FLAG_GENPTS; AVCodecContext *ctx = NULL; for(i = 0; i < fctx->nb_streams; i++) { if(fctx->streams[i]->codec != NULL && fctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { ctx = fctx->streams[i]->codec; break; } } if(ctx == NULL) { fa_libav_close_format(fctx); return NULL; } AVCodec *codec = avcodec_find_decoder(ctx->codec_id); if(codec == NULL) { fa_libav_close_format(fctx); snprintf(errbuf, errlen, "Unable to find codec"); return NULL; } if(avcodec_open(ctx, codec) < 0) { fa_libav_close_format(fctx); snprintf(errbuf, errlen, "Unable to open codec"); return NULL; } ifv_close(); ifv_stream = i; ifv_url = strdup(url); ifv_fctx = fctx; ifv_ctx = ctx; } AVPacket pkt; AVFrame *frame = avcodec_alloc_frame(); int got_pic; AVStream *st = ifv_fctx->streams[ifv_stream]; int64_t ts = av_rescale(sec, st->time_base.den, st->time_base.num); if(av_seek_frame(ifv_fctx, ifv_stream, ts, AVSEEK_FLAG_BACKWARD) < 0) { ifv_close(); snprintf(errbuf, errlen, "Unable to seek to %"PRId64, ts); return NULL; } avcodec_flush_buffers(ifv_ctx); #define MAX_FRAME_SCAN 500 int cnt = MAX_FRAME_SCAN; while(1) { int r; r = av_read_frame(ifv_fctx, &pkt); if(r == AVERROR(EAGAIN)) continue; if(r == AVERROR_EOF) { break; } if(cb != NULL && cb(opaque, 0, 1)) { snprintf(errbuf, errlen, "Aborted"); break; } if(r != 0) { ifv_close(); break; } if(pkt.stream_index != ifv_stream) { av_free_packet(&pkt); continue; } cnt--; int want_pic = pkt.pts >= ts || cnt <= 0; ifv_ctx->skip_frame = want_pic ? AVDISCARD_DEFAULT : AVDISCARD_NONREF; avcodec_decode_video2(ifv_ctx, frame, &got_pic, &pkt); av_free_packet(&pkt); if(got_pic == 0 || !want_pic) { continue; } int w,h; if(im->im_req_width != -1 && im->im_req_height != -1) { w = im->im_req_width; h = im->im_req_height; } else if(im->im_req_width != -1) { w = im->im_req_width; h = im->im_req_width * ifv_ctx->height / ifv_ctx->width; } else if(im->im_req_height != -1) { w = im->im_req_height * ifv_ctx->width / ifv_ctx->height; h = im->im_req_height; } else { w = im->im_req_width; h = im->im_req_height; } pm = pixmap_create(w, h, PIXMAP_RGB24, #ifdef __PPC__ 16 #else 1 #endif ); if(pm == NULL) { ifv_close(); snprintf(errbuf, errlen, "Out of memory"); return NULL; } struct SwsContext *sws; sws = sws_getContext(ifv_ctx->width, ifv_ctx->height, ifv_ctx->pix_fmt, w, h, PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL); if(sws == NULL) { ifv_close(); snprintf(errbuf, errlen, "Scaling failed"); pixmap_release(pm); return NULL; } uint8_t *ptr[4] = {0,0,0,0}; int strides[4] = {0,0,0,0}; ptr[0] = pm->pm_pixels; strides[0] = pm->pm_linesize; sws_scale(sws, (const uint8_t **)frame->data, frame->linesize, 0, ifv_ctx->height, ptr, strides); sws_freeContext(sws); if(pngencoder != NULL) { AVFrame *oframe = avcodec_alloc_frame(); memset(&frame, 0, sizeof(frame)); oframe->data[0] = pm->pm_pixels; oframe->linesize[0] = pm->pm_linesize; size_t outputsize = MAX(pm->pm_linesize * h, FF_MIN_BUFFER_SIZE); void *output = malloc(outputsize); pngencoder->width = w; pngencoder->height = h; pngencoder->pix_fmt = PIX_FMT_RGB24; r = avcodec_encode_video(pngencoder, output, outputsize, oframe); if(r > 0) blobcache_put(cacheid, "videothumb", output, r, INT32_MAX, NULL, mtime); free(output); av_free(oframe); } break; } av_free(frame); if(pm == NULL) snprintf(errbuf, errlen, "Frame not found (scanned %d)", MAX_FRAME_SCAN - cnt); return pm; }
pixmap_t * fa_imageloader(const char *url, const struct image_meta *im, const char **vpaths, char *errbuf, size_t errlen) { uint8_t p[16]; int r; enum CodecID codec; int width = -1, height = -1, orientation = 0; AVIOContext *avio; pixmap_t *pm; if(strchr(url, '#')) { pm = fa_image_from_video(url, im); if(pm == NULL) snprintf(errbuf, errlen, "%s: Unable to extract image", url); return pm; } if(!im->want_thumb) return fa_imageloader2(url, vpaths, errbuf, errlen); if((avio = fa_libav_open_vpaths(url, 32768, vpaths)) == NULL) { snprintf(errbuf, errlen, "%s: Unable to open file", url); return NULL; } if(avio_read(avio, p, sizeof(p)) != sizeof(p)) { snprintf(errbuf, errlen, "%s: file too short", url); fa_libav_close(avio); return NULL; } /* Probe format */ if((p[6] == 'J' && p[7] == 'F' && p[8] == 'I' && p[9] == 'F') || (p[6] == 'E' && p[7] == 'x' && p[8] == 'i' && p[9] == 'f')) { jpeginfo_t ji; if(jpeg_info(&ji, jpeginfo_reader, avio, JPEG_INFO_DIMENSIONS | JPEG_INFO_ORIENTATION | (im->want_thumb ? JPEG_INFO_THUMBNAIL : 0), p, sizeof(p), errbuf, errlen)) { fa_libav_close(avio); return NULL; } if(im->want_thumb && ji.ji_thumbnail) { pixmap_t *pm = pixmap_dup(ji.ji_thumbnail); fa_libav_close(avio); jpeg_info_clear(&ji); return pm; } codec = CODEC_ID_MJPEG; width = ji.ji_width; height = ji.ji_height; orientation = ji.ji_orientation; jpeg_info_clear(&ji); } else if(!memcmp(pngsig, p, 8)) { codec = CODEC_ID_PNG; } else if(!memcmp(gif87sig, p, sizeof(gif87sig)) || !memcmp(gif89sig, p, sizeof(gif89sig))) { codec = CODEC_ID_GIF; } else { snprintf(errbuf, errlen, "%s: unknown format", url); fa_libav_close(avio); return NULL; } size_t s = avio_size(avio); if(s < 0) { snprintf(errbuf, errlen, "%s: Can't read from non-seekable file", url); fa_libav_close(avio); return NULL; } pm = pixmap_alloc_coded(NULL, s, codec); if(pm == NULL) { snprintf(errbuf, errlen, "%s: no memory", url); fa_libav_close(avio); return NULL; } pm->pm_width = width; pm->pm_height = height; pm->pm_orientation = orientation; avio_seek(avio, SEEK_SET, 0); r = avio_read(avio, pm->pm_data, pm->pm_size); fa_libav_close(avio); if(r != pm->pm_size) { pixmap_release(pm); snprintf(errbuf, errlen, "%s: read error", url); return NULL; } return pm; }