static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { int i, tmp, stretchx, stretchy; framenum = 0; if (format != IMGFMT_YV12 && format != IMGFMT_YUY2) { printf("vo_zr called with wrong format"); return 1; } for (i = 0; i < zr_count; i++) { zr_info_t *zr = &zr_info[i]; geo_t *g = &zr->g; zr->stride = 2*width; if (zr_geometry_sane(g, width, height)) return 1; /* we must know the maximum resolution of the device * it differs for DC10+ and buz for example */ zoran_getcap(zr); /*must be called before init_zoran */ /* make the scaling decision * we are capable of stretching the image in the horizontal * direction by factors 1, 2 and 4 * we can stretch the image in the vertical direction by a * factor of 1 and 2 AND we must decide about interlacing */ if (g->width > zr->vc.maxwidth/2 || g->height > zr->vc.maxheight/2) { stretchx = 1; stretchy = 1; zr->fields = 2; if (zr->vdec == 2) { zr->fields = 1; } else if (zr->vdec == 4) { zr->fields = 1; stretchy = 2; } stretchx = zr->hdec; } else if (g->width > zr->vc.maxwidth/4 || g->height > zr->vc.maxheight/4) { stretchx = 2; stretchy = 1; zr->fields = 1; if (zr->vdec == 2) { stretchy = 2; } else if (zr->vdec == 4) { if (!zr->fd) { mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 2 (use -zrfd to keep vdec=4)\n"); zr->vdec = 2; } stretchy = 2; } if (zr->hdec == 2) { stretchx = 4; } else if (zr->hdec == 4){ if (!zr->fd) { mp_msg(MSGT_VO, MSGL_WARN, "zr: horizontal decimation too high, changing to 2 (use -zrfd to keep hdec=4)\n"); zr->hdec = 2; } stretchx = 4; } } else { /* output image is maximally stretched */ stretchx = 4; stretchy = 2; zr->fields = 1; if (zr->vdec != 1 && !zr->fd) { mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 1 (use -zrfd to keep vdec=%d)\n", zr->vdec); zr->vdec = 1; } if (zr->hdec != 1 && !zr->fd) { mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 1 (use -zrfd to keep hdec=%d)\n", zr->hdec); zr->hdec = 1; } } /* It can be that the original frame was too big for display, * or that the width of the decimated image (for example) after * padding up to a multiple of 16 has become too big. (orig * width 720 (exactly right for the Buz) after decimation 360, * after padding up to a multiple of 16 368, display 736 -> too * large). In these situations we auto(re)crop. */ tmp = 16*((g->width - 1)/(zr->hdec*16) + 1); if (stretchx*tmp > zr->vc.maxwidth) { g->xoff += 2*((g->width - zr->hdec*(tmp-16))/4); /* g->off must be a multiple of 2 */ g->width = zr->hdec*(tmp - 16); g->set = 0; /* we abuse this field to report that g has changed*/ } tmp = 8*zr->fields*((g->height - 1)/(zr->vdec*zr->fields*8)+1); if (stretchy*tmp > zr->vc.maxheight) { g->yoff += 2*((g->height - zr->vdec* (tmp - 8*zr->fields))/4); g->height = zr->vdec*(tmp - 8*zr->fields); g->set = 0; } if (!g->set) mp_msg(MSGT_VO, MSGL_V, "zr: auto(re)cropping %dx%d+%d+%d to make the image fit on the screen\n", g->width, g->height, g->xoff, g->yoff); /* the height must be a multiple of fields*8 and the width * must be a multiple of 16 */ /* add some black borders to make it so, and center the image*/ zr->image_height = zr->fields*8*((g->height/zr->vdec - 1)/ (zr->fields*8) + 1); zr->image_width = (zr->hdec*16)*((g->width - 1)/(zr->hdec*16) + 1); zr->off_y = (zr->image_height - g->height/zr->vdec)/2; if (zr->off_y%2 != 0) zr->off_y++; zr->off_y *= zr->image_width; zr->off_c = zr->off_y/4; zr->off_y += (zr->image_width - g->width)/2; if (zr->off_y%2 != 0) zr->off_y--; zr->off_c += (zr->image_width - g->width)/4; zr->size = zr->image_width*zr->image_height; mp_msg(MSGT_VO, MSGL_V, "zr: input: %dx%d, cropped: %dx%d, output: %dx%d, off_y=%d, off_c=%d\n", width, height, g->width, g->height, zr->image_width, zr->image_height, zr->off_y, zr->off_c); zr->image = malloc(2*zr->size); /* this buffer allows for YUV422 data, * so it is a bit too big for YUV420 */ if (!zr->image) { mp_msg(MSGT_VO, MSGL_ERR, "zr: Memory exhausted\n"); return 1; } /* and make sure that the borders are _really_ black */ switch (format) { case IMGFMT_YV12: memset(zr->image, 0, zr->size); memset(zr->image + zr->size, 0x80, zr->size/4); memset(zr->image + 3*zr->size/2, 0x80, zr->size/4); zr->y_data = zr->image; zr->u_data = zr->image + zr->size; zr->v_data = zr->image + 3*zr->size/2; zr->y_stride = zr->image_width; zr->u_stride = zr->image_width/2; zr->v_stride = zr->image_width/2; zr->j = jpeg_enc_init(zr->image_width/zr->hdec, zr->image_height/zr->fields, zr->hdec, zr->y_stride*zr->fields, zr->hdec, zr->u_stride*zr->fields, zr->hdec, zr->v_stride*zr->fields, 1, zr->quality, zr->bw); break; case IMGFMT_YUY2: for (tmp = 0; tmp < 2*zr->size; tmp+=4) { zr->image[tmp] = 0; zr->image[tmp+1] = 0x80; zr->image[tmp+2] = 0; zr->image[tmp+3] = 0x80; } zr->y_data = zr->image; zr->u_data = zr->image + 1; zr->v_data = zr->image + 3; zr->y_stride = 2*zr->image_width; zr->u_stride = 2*zr->image_width; zr->v_stride = 2*zr->image_width; zr->j = jpeg_enc_init(zr->image_width/zr->hdec, zr->image_height/zr->fields, zr->hdec*2, zr->y_stride*zr->fields, zr->hdec*4, zr->u_stride*zr->fields, zr->hdec*4, zr->v_stride*zr->fields, 0, zr->quality, zr->bw); break; default: mp_msg(MSGT_VO, MSGL_FATAL, "zr: internal inconsistency in vo_zr\n"); } if (zr->j == NULL) { mp_msg(MSGT_VO, MSGL_ERR, "zr: error initializing the jpeg encoder\n"); return 1; } if (init_zoran(zr, stretchx, stretchy)) { return 1; } } return 0; }
/** * \param vf video filter instance pointer * \param width image source width in pixels * \param height image source height in pixels * \param d_width width of requested window, just a hint * \param d_height height of requested window, just a hint * \param flags vf filter flags * \param outfmt * * \returns returns 0 on error * * This routine will make the necessary hardware-related decisions for * the ZRMJPEG filter, do the initialization of the MJPEG encoder, and * then select one of the ZRJMJPEGIT or ZRMJPEGNI filters and then * arrange to dispatch to the config() entry pointer for the one * selected. */ static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt){ struct vf_priv_s *priv = vf->priv; float aspect_decision; int stretchx, stretchy, err = 0, maxstretchx = 4; priv->fields = 1; VERBOSE("config() called\n"); if (priv->j) { VERBOSE("re-configuring, resetting JPEG encoder\n"); jpeg_enc_uninit(priv->j); priv->j = NULL; } aspect_decision = ((float)d_width/(float)d_height)/ ((float)width/(float)height); if (aspect_decision > 1.8 && aspect_decision < 2.2) { VERBOSE("should correct aspect by stretching x times 2, %d %d\n", 2*width, priv->maxwidth); if (2*width <= priv->maxwidth) { d_width = 2*width; d_height = height; maxstretchx = 2; } else { WARNING("unable to correct aspect by stretching, because resulting X will be too large, aspect correction by decimating y not yet implemented\n"); d_width = width; d_height = height; } /* prestretch movie */ } else { /* uncorrecting output for now */ d_width = width; d_height = height; } /* make the scaling decision * we are capable of stretching the image in the horizontal * direction by factors 1, 2 and 4 * we can stretch the image in the vertical direction by a * factor of 1 and 2 AND we must decide about interlacing */ if (d_width > priv->maxwidth/2 || height > priv->maxheight/2 || maxstretchx == 1) { stretchx = 1; stretchy = 1; priv->fields = 2; if (priv->vdec == 2) { priv->fields = 1; } else if (priv->vdec == 4) { priv->fields = 1; stretchy = 2; } if (priv->hdec > maxstretchx) { if (priv->fd) { WARNING("horizontal decimation too high, " "changing to %d (use fd to keep" " hdec=%d)\n", maxstretchx, priv->hdec); priv->hdec = maxstretchx; } } stretchx = priv->hdec; } else if (d_width > priv->maxwidth/4 || height > priv->maxheight/4 || maxstretchx == 2) { stretchx = 2; stretchy = 1; priv->fields = 1; if (priv->vdec == 2) { stretchy = 2; } else if (priv->vdec == 4) { if (!priv->fd) { WARNING("vertical decimation too high, " "changing to 2 (use fd to keep " "vdec=4)\n"); priv->vdec = 2; } stretchy = 2; } if (priv->hdec == 2) { stretchx = 4; } else if (priv->hdec == 4) { if (priv->fd) { WARNING("horizontal decimation too high, " "changing to 2 (use fd to keep " "hdec=4)\n"); priv->hdec = 2; } stretchx = 4; } } else { /* output image is maximally stretched */ stretchx = 4; stretchy = 2; priv->fields = 1; if (priv->vdec != 1 && !priv->fd) { WARNING("vertical decimation too high, changing to 1 " "(use fd to keep vdec=%d)\n", priv->vdec); priv->vdec = 1; } if (priv->hdec != 1 && !priv->fd) { WARNING("horizontal decimation too high, changing to 1 (use fd to keep hdec=%d)\n", priv->hdec); priv->hdec = 1; } } VERBOSE("generated JPEG's %dx%s%d%s, stretched to %dx%d\n", width/priv->hdec, (priv->fields == 2) ? "(" : "", height/(priv->vdec*priv->fields), (priv->fields == 2) ? "x2)" : "", (width/priv->hdec)*stretchx, (height/(priv->vdec*priv->fields))* stretchy*priv->fields); if ((width/priv->hdec)*stretchx > priv->maxwidth || (height/(priv->vdec*priv->fields))* stretchy*priv->fields > priv->maxheight) { ERROR("output dimensions too large (%dx%d), max (%dx%d) " "insert crop to fix\n", (width/priv->hdec)*stretchx, (height/(priv->vdec*priv->fields))* stretchy*priv->fields, priv->maxwidth, priv->maxheight); err = 1; } if (width%(16*priv->hdec) != 0) { ERROR("width must be a multiple of 16*hdec (%d), use expand\n", priv->hdec*16); err = 1; } if (height%(8*priv->fields*priv->vdec) != 0) { ERROR("height must be a multiple of 8*fields*vdec (%d)," " use expand\n", priv->vdec*priv->fields*8); err = 1; } if (err) return 0; priv->y_stride = width; priv->c_stride = width/2; priv->j = jpeg_enc_init(width, height/priv->fields, priv->fields*priv->y_stride, priv->fields*priv->c_stride, priv->fields*priv->c_stride, 1, priv->quality, priv->bw); if (!priv->j) return 0; return vf_next_config(vf, width, height, d_width, d_height, flags, (priv->fields == 2) ? IMGFMT_ZRMJPEGIT : IMGFMT_ZRMJPEGNI); }