Monday, February 23, 2009

mplayer screenshot name

About a year ago a friend of mine complained of the filename style for screenshots by mplayer. He said it should contain the original file name and a timestamp (so one could easily watch screenshoted scene once again). I hacked mplayer but unfortunately the patch didn't get accepted to the mainline.

Here is the patch anyway:

Index: libmpcodecs/vf_screenshot.c
===================================================================
--- libmpcodecs/vf_screenshot.c (revision 28346)
+++ libmpcodecs/vf_screenshot.c (working copy)
@@ -22,9 +22,19 @@
#include "libswscale/swscale.h"
#include "libavcodec/avcodec.h"

+#include "m_option.h"
+#include "m_struct.h"
+
+#include "mplayer.h"
+
+#define SHOT_FNAME_LENGTH 102
+#define TIMESTAMP_LENGTH 20
+
struct vf_priv_s {
int frameno;
- char fname[102];
+ char *fname;
+ char *basename;
+ int style;
/// shot stores current screenshot mode:
/// 0: don't take screenshots
/// 1: take single screenshot, reset to 0 afterwards
@@ -36,7 +46,7 @@
AVCodecContext *avctx;
uint8_t *outbuffer;
int outbuffer_size;
-};
+} vf_priv_dflt;

//===========================================================================//

@@ -92,14 +102,65 @@
else return 0;
}

-static void gen_fname(struct vf_priv_s* priv)
+static void gen_fname(struct vf_priv_s* priv, double pts)
{
- do {
- snprintf (priv->fname, 100, "shot%04d.png", ++priv->frameno);
- } while (fexists(priv->fname) && priv->frameno < 100000);
- if (fexists(priv->fname)) {
- priv->fname[0] = '\0';
- return;
+ char *base = "shot";
+ char tstamp[TIMESTAMP_LENGTH];
+ char ts_sep;
+ uint32_t hour = (uint32_t) (pts/3600);
+ uint32_t min = (uint32_t) (pts/60) % 60;
+ uint32_t sec = (uint32_t) pts % 60;
+ uint32_t msec = (uint32_t) (pts*100) % 100;
+ size_t n;
+
+ switch (priv->style) {
+ case 1:
+ case 2:
+ ts_sep = (priv->style == 1) ? ':' : '-';
+ /* TIMESTAMP_LENGTH is enough for 2^32 seconds */
+ snprintf(tstamp, TIMESTAMP_LENGTH,
+ "%02" PRIu32 "%c%02" PRIu32 "%c%02" PRIu32 ".%02" PRIu32,
+ hour, ts_sep, min, ts_sep, sec, msec);
+
+ if (priv->basename)
+ base = priv->basename;
+ else {
+ if (strstr(filename, "://"))
+ base = "shot";
+ else {
+ base = strrchr(filename, '/');
+ if (base == NULL)
+ base = filename;
+ else
+ base++;
+ }
+ }
+
+ /* 8 is length of ".[].png" plus '\0' */
+ n = strlen(base) + strlen(tstamp) + 8;
+ priv->fname = malloc(n);
+ if (!priv->fname) {
+ mp_msg(MSGT_VFILTER,MSGL_ERR,"Unable to allocate memory in vf_screenshot.c\n");
+ return;
+ }
+ snprintf(priv->fname, n, "%s.[%s].png", base, tstamp);
+ break;
+ default:
+ case 0:
+ priv->fname = malloc(SHOT_FNAME_LENGTH);
+ if (!priv->fname) {
+ mp_msg(MSGT_VFILTER,MSGL_ERR,"Unable to allocate memory in vf_screenshot.c\n");
+ return;
+ }
+ do {
+ snprintf (priv->fname, SHOT_FNAME_LENGTH, "shot%04d.png", ++priv->frameno);
+ } while (fexists(priv->fname) && priv->frameno < 100000);
+ if (fexists(priv->fname)) {
+ free(priv->fname);
+ priv->fname = NULL;
+ return;
+ }
+ break;
}

mp_msg(MSGT_VFILTER,MSGL_INFO,"*** screenshot '%s' ***\n",priv->fname);
@@ -196,11 +257,13 @@
if(vf->priv->shot) {
if (vf->priv->shot==1)
vf->priv->shot=0;
- gen_fname(vf->priv);
- if (vf->priv->fname[0]) {
+ gen_fname(vf->priv, pts);
+ if (vf->priv->fname) {
if (!vf->priv->store_slices)
scale_image(vf->priv, dmpi);
write_png(vf->priv);
+ free(vf->priv->fname);
+ vf->priv->fname = NULL;
}
vf->priv->store_slices = 0;
}
@@ -263,6 +326,8 @@
av_freep(&vf->priv->avctx);
if(vf->priv->ctx) sws_freeContext(vf->priv->ctx);
if (vf->priv->buffer) free(vf->priv->buffer);
+ if (vf->priv->fname) free(vf->priv->fname);
+ if (vf->priv->basename) free(vf->priv->basename);
free(vf->priv->outbuffer);
free(vf->priv);
}
@@ -278,7 +343,7 @@
vf->draw_slice=draw_slice;
vf->get_image=get_image;
vf->uninit=uninit;
- vf->priv=malloc(sizeof(struct vf_priv_s));
+ if (!vf->priv) vf->priv = calloc(1, sizeof(struct vf_priv_s));
vf->priv->frameno=0;
vf->priv->shot=0;
vf->priv->store_slices=0;
@@ -294,14 +359,27 @@
return 1;
}

+#define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
+static const m_option_t vf_opts_fields[] = {
+ {"style", ST_OFF(style), CONF_TYPE_INT, 0, 0, 2, NULL},
+ {"basename", ST_OFF(basename), CONF_TYPE_STRING, 0, M_OPT_MIN, M_OPT_MAX, NULL},
+ {NULL, NULL, 0, 0, 0, 0, NULL}
+};

+static const m_struct_t vf_opts = {
+ "screenshot",
+ sizeof(struct vf_priv_s),
+ &vf_priv_dflt,
+ vf_opts_fields
+};
+
const vf_info_t vf_info_screenshot = {
"screenshot to file",
"screenshot",
"A'rpi, Jindrich Makovicka",
"",
screenshot_open,
- NULL
+ &vf_opts
};

//===========================================================================//
Index: DOCS/man/en/mplayer.1
===================================================================
--- DOCS/man/en/mplayer.1 (revision 28346)
+++ DOCS/man/en/mplayer.1 (working copy)
@@ -7180,15 +7180,28 @@
.RE
.
.TP
-.B screenshot
+.B screenshot[=style:basename]
Allows acquiring screenshots of the movie using slave mode
commands that can be bound to keypresses.
See the slave mode documentation and the INTERACTIVE CONTROL
section for details.
-Files named 'shotNNNN.png' will be saved in the working directory,
-using the first available number \- no files will be overwritten.
The filter has no overhead when not used and accepts an arbitrary
colorspace, so it is safe to add it to the configuration file.
+.RSs
+.IPs <style>
+0: Files named 'shotNNNN.png' will be saved in the working directory,
+using the first available number \- no files will be overwritten.
+.br
+1: Files named 'basename.[hh:mm:ss.ms].png' will be saved in the
+working directory.
+.br
+2: Files named 'basename.[hh-mm-ss.ms].png' will be saved in the
+working directory. Use this if your environment doesn't allow colon
+in filenames.
+.IPs <basename>
+Basename for a screenshot file. If not set and mplayer is playing a file,
+the file name will be used. If not set and mplayer is playing a stream,
+"shot" will be used.
.RE
.
.TP
Index: mencoder.c
===================================================================
--- mencoder.c (revision 28346)
+++ mencoder.c (working copy)
@@ -115,6 +115,7 @@
char* audio_lang=NULL;
char* dvdsub_lang=NULL;
static char* spudec_ifo=NULL;
+char* filename=NULL;

static char** audio_codec_list=NULL; // override audio codec
static char** video_codec_list=NULL; // override video codec
@@ -397,7 +398,6 @@
double v_timer_corr=0;

m_entry_t* filelist = NULL;
-char* filename=NULL;

int decoded_frameno=0;
int next_frameno=-1;

No comments: