/** * Put a video frame into the video mixer * * @param src Video source * @param frame Video frame */ void vidmix_source_put(struct vidmix_source *src, const struct vidframe *frame) { if (!src || !frame || frame->fmt != VID_FMT_YUV420P) return; if (!src->frame_rx || !vidsz_cmp(&src->frame_rx->size, &frame->size)) { struct vidframe *frm; int err; err = vidframe_alloc(&frm, VID_FMT_YUV420P, &frame->size); if (err) return; pthread_rwlock_wrlock(&src->mix->rwlock); mem_deref(src->frame_rx); src->frame_rx = frm; clear_all(src->mix); pthread_rwlock_unlock(&src->mix->rwlock); } vidframe_copy(src->frame_rx, frame); }
static int encode_pip(struct vidfilt_enc_st *st, struct vidframe *frame) { struct selfview_enc *enc = (struct selfview_enc *)st; struct selfview *selfview = enc->selfview; int err = 0; if (!frame) return 0; lock_write_get(selfview->lock); if (!selfview->frame) { struct vidsz sz; /* Use size if configured, or else 20% of main window */ if (selfview_size.w && selfview_size.h) { sz = selfview_size; } else { sz.w = frame->size.w / 5; sz.h = frame->size.h / 5; } err = vidframe_alloc(&selfview->frame, VID_FMT_YUV420P, &sz); } if (!err) vidconv(selfview->frame, frame, NULL); lock_rel(selfview->lock); return err; }
static int draw_text(struct panel *panel, struct vidframe *frame) { char buf[256]; int width = panel->size_text.w; int height = panel->size_text.h; struct vidframe f; struct vidframe *f2 = NULL; cairo_t *cr = panel->cr; double tx, ty; int err; tx = 1; ty = height - 3; /* draw background */ cairo_rectangle (cr, 0, 0, width, height); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_fill (cr); /* Draw text */ if (re_snprintf(buf, sizeof(buf), "%s %2.2f fps", panel->label, panel->fps) < 0) return ENOMEM; cairo_move_to (cr, tx, ty); cairo_text_path (cr, buf); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_fill_preserve (cr); cairo_set_line_width (cr, 0.6); cairo_stroke (cr); vidframe_init_buf(&f, VID_FMT_ARGB, &panel->size_text, cairo_image_surface_get_data(panel->surface)); err = vidframe_alloc(&f2, frame->fmt, &panel->size_text); if (err) goto out; vidconv(f2, &f, 0); overlay(frame, panel->yoffs, f2); out: mem_deref(f2); return err; }
static int src_alloc(struct vidsrc_st **stp, const struct vidsrc *vs, struct media_ctx **ctx, struct vidsrc_prm *prm, const struct vidsz *size, const char *fmt, const char *dev, vidsrc_frame_h *frameh, vidsrc_error_h *errorh, void *arg) { struct vidsrc_st *st; int err; (void)ctx; (void)fmt; (void)dev; (void)errorh; if (!stp || !prm || !size || !frameh) return EINVAL; st = mem_zalloc(sizeof(*st), src_destructor); if (!st) return ENOMEM; st->vs = vs; st->fps = prm->fps; st->frameh = frameh; st->arg = arg; err = vidframe_alloc(&st->frame, VID_FMT_YUV420P, size); if (err) goto out; st->run = true; err = pthread_create(&st->thread, NULL, read_thread, st); if (err) { st->run = false; goto out; } out: if (err) mem_deref(st); else *stp = st; return err; }
static int plot_spectrum(const char *filename_png) { struct vidframe *vf = NULL; struct vidsz sz = {NUM_FREQ+1, NUM_FREQ/2}; unsigned long peak_mag = 0; size_t peak_bin = 0; size_t i; unsigned x; int err; err = vidframe_alloc(&vf, VID_FMT_RGB32, &sz); if (err) goto out; /* find the peak amplitude and its bin */ for (i=0; i<NUM_FREQ; i++) { if (magv[i] > peak_mag) { peak_mag = magv[i]; peak_bin = i; } } re_printf("peak magnitude is %u in bin %u\n", peak_mag, peak_bin); vidframe_fill(vf, 255, 255, 255); for (x=0; x<NUM_FREQ; x++) { unsigned h; h = (unsigned)((sz.h-1) * 1.0 * magv[x] / peak_mag); vidframe_draw_vline(vf, x, sz.h-1-h, h, 255, 0, 0); } err = png_save_vidframe(vf, filename_png); if (err) goto out; out: mem_deref(vf); return err; }
/** * Allocate a video mixer source * * @param srcp Pointer to allocated video source * @param mix Video mixer * @param sz Size of output video frame (optional) * @param fps Output frame rate (frames per second) * @param content True if source is of type content * @param fh Mixer frame handler * @param arg Handler argument * * @return 0 for success, otherwise error code */ int vidmix_source_alloc(struct vidmix_source **srcp, struct vidmix *mix, const struct vidsz *sz, unsigned fps, bool content, vidmix_frame_h *fh, void *arg) { struct vidmix_source *src; int err; if (!srcp || !mix || !fps || !fh) return EINVAL; src = mem_zalloc(sizeof(*src), source_destructor); if (!src) return ENOMEM; src->mix = mem_ref(mix); src->fint = 1000/fps; src->content = content; src->fh = fh; src->arg = arg; err = pthread_mutex_init(&src->mutex, NULL); if (err) goto out; if (sz) { err = vidframe_alloc(&src->frame_tx, VID_FMT_YUV420P, sz); if (err) goto out; clear_frame(src->frame_tx); } out: if (err) mem_deref(src); else *srcp = src; return err; }
static int encode_pip(struct vidfilt_st *st, struct vidframe *frame) { struct selfview *sv = (struct selfview *)st; int err = 0; if (!frame) return 0; lock_write_get(sv->lock); if (!sv->frame) { struct vidsz sz; sz.w = frame->size.w / 5; sz.h = frame->size.h / 5; err = vidframe_alloc(&sv->frame, VID_FMT_YUV420P, &sz); } if (!err) vidconv(sv->frame, frame, NULL); lock_rel(sv->lock); return err; }
/** * Set video mixer output frame size * * @param src Video mixer source * @param sz Size of output video frame * * @return 0 for success, otherwise error code */ int vidmix_source_set_size(struct vidmix_source *src, const struct vidsz *sz) { struct vidframe *frame; int err; if (!src || !sz) return EINVAL; if (src->frame_tx && vidsz_cmp(&src->frame_tx->size, sz)) return 0; err = vidframe_alloc(&frame, VID_FMT_YUV420P, sz); if (err) return err; clear_frame(frame); pthread_mutex_lock(&src->mutex); mem_deref(src->frame_tx); src->frame_tx = frame; pthread_mutex_unlock(&src->mutex); return 0; }
static int encode_process(struct vidfilt_enc_st *st, struct vidframe *frame) { struct swscale_enc *enc = (struct swscale_enc *)st; enum AVPixelFormat avpixfmt, avpixfmt_dst; const uint8_t *srcSlice[4]; uint8_t *dst[4]; int srcStride[4], dstStride[4]; int width, height, i, h; int err = 0; if (!st) return EINVAL; if (!frame) return 0; width = frame->size.w; height = frame->size.h; avpixfmt = vidfmt_to_avpixfmt(frame->fmt); if (avpixfmt == AV_PIX_FMT_NONE) { warning("swscale: unknown pixel-format (%s)\n", vidfmt_name(frame->fmt)); return EINVAL; } avpixfmt_dst = vidfmt_to_avpixfmt(swscale_format); if (avpixfmt_dst == AV_PIX_FMT_NONE) { warning("swscale: unknown pixel-format (%s)\n", vidfmt_name(swscale_format)); return EINVAL; } if (!enc->sws) { struct SwsContext *sws; int flags = 0; sws = sws_getContext(width, height, avpixfmt, enc->dst_size.w, enc->dst_size.h, avpixfmt_dst, flags, NULL, NULL, NULL); if (!sws) { warning("swscale: sws_getContext error\n"); return ENOMEM; } enc->sws = sws; info("swscale: created SwsContext:" " `%s' %d x %d --> `%s' %u x %u\n", vidfmt_name(frame->fmt), width, height, vidfmt_name(swscale_format), enc->dst_size.w, enc->dst_size.h); } if (!enc->frame) { err = vidframe_alloc(&enc->frame, swscale_format, &enc->dst_size); if (err) { warning("swscale: vidframe_alloc error (%m)\n", err); return err; } } for (i=0; i<4; i++) { srcSlice[i] = frame->data[i]; srcStride[i] = frame->linesize[i]; dst[i] = enc->frame->data[i]; dstStride[i] = enc->frame->linesize[i]; } h = sws_scale(enc->sws, srcSlice, srcStride, 0, height, dst, dstStride); if (h <= 0) { warning("swscale: sws_scale error (%d)\n", h); return EPROTO; } /* Copy the converted frame back to the input frame */ for (i=0; i<4; i++) { frame->data[i] = enc->frame->data[i]; frame->linesize[i] = enc->frame->linesize[i]; } frame->size = enc->frame->size; frame->fmt = enc->frame->fmt; return 0; }
int png_save_vidframe(const struct vidframe *vf, const char *filename) { png_byte **png_row_pointers = NULL; png_byte *row; const png_byte *p; png_byte red, green, blue; png_structp png_ptr = NULL; png_infop info_ptr = NULL; FILE *fp = NULL; size_t x, y; unsigned int width = vf->size.w & ~1; unsigned int height = vf->size.h & ~1; unsigned int bytes_per_pixel = 3; /* RGB format */ struct vidframe *f2 = NULL; int err = 0; if (vf->fmt != VID_FMT_RGB32) { err = vidframe_alloc(&f2, VID_FMT_RGB32, &vf->size); if (err) goto out; vidconv(f2, vf, NULL); vf = f2; } /* Initialize the write struct. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { err = ENOMEM; goto out; } /* Initialize the info struct. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { err = ENOMEM; goto out; } /* Set up error handling. */ if (setjmp(png_jmpbuf(png_ptr))) { err = ENOMEM; goto out; } /* Set image attributes. */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Initialize rows of PNG * bytes_per_row = width * bytes_per_pixel; */ png_row_pointers = png_malloc(png_ptr, height * sizeof(png_byte *)); for (y = 0; y < height; ++y) { png_row_pointers[y] = (png_byte *) png_malloc(png_ptr, width * sizeof(uint8_t) * bytes_per_pixel); } p = vf->data[0]; for (y = 0; y < height; ++y) { row = png_row_pointers[y]; for (x = 0; x < width; ++x) { red = *p++; green = *p++; blue = *p++; *row++ = blue; *row++ = green; *row++ = red; ++p; /* skip alpha */ } } /* Write the image data. */ fp = fopen(filename, "wb"); if (fp == NULL) { err = errno; goto out; } png_init_io(png_ptr, fp); png_set_rows(png_ptr, info_ptr, png_row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); re_printf("wrote %u x %u pixels to %s\n", vf->size.w, vf->size.h, filename); out: /* Finish writing. */ mem_deref(f2); png_save_free(png_ptr, png_row_pointers, height); png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) fclose(fp); return 0; }
int jpg_save_vidframe(const struct vidframe *vf, const char *path) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; unsigned char *imgdata,*src,*dst; int row_stride,pixs; FILE * fp; char filename_buf[64]; struct vidframe *f2 = NULL; int err = 0; unsigned int width = vf->size.w & ~1; unsigned int height = vf->size.h & ~1; time_t tnow; struct tm *tmx; // 0 tnow = time(NULL); tmx = localtime(&tnow); imgdata = vf->data[0]; if (vf->fmt != VID_FMT_RGB32) { err = vidframe_alloc(&f2, VID_FMT_RGB32, &vf->size); if (err) goto out; vidconv(f2, vf, NULL); imgdata = f2->data[0]; } fp = fopen(jpg_filename(tmx, path, filename_buf, sizeof(filename_buf)), "wb"); if (fp == NULL) { err = errno; goto out; } // 32bpp -> 24bpp pixs = width*height; src = imgdata; dst = imgdata; while (pixs--) { *dst++=*src++; //R *dst++=*src++; //G *dst++=*src++; //B src++; //A } // create jpg structures cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; // 24 bpp // I wonder if this will make double conversion. cinfo.in_color_space = JCS_EXT_BGR; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 85 , TRUE); // quality 85% // compress jpeg_start_compress(&cinfo, TRUE); row_stride = width * cinfo.input_components; //buffer = (JSAMPARRAY) imgdata; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = & imgdata[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); /* Finish writing. */ out: jpeg_destroy_compress(&cinfo); mem_deref(f2); if (fp) fclose(fp); return 0; }