Hi everyone,
Over the past months, I have done a fair but of tweaking and
customization with my Freevo setup. One of the areas I still wasn't
satisfied with was that of TV recording, since I'm not as lucky as
others that have a TV card that does hardware mpeg2 encoding. :) The
problem lies in the 2G AVI limitation with mplayer. Specifically
mplayer/mencoder doesn't support indexing past 2G, so while you can
record and play AVIs that big, you lose the ability to seek in them.
So, in my script that calls mencoder, I must use CBR, instead of
constant quantizing, because although I have the CPU power to encode
with qscale in real-time, I need to ensure the file size doesn't exceed
2G in a 2 hour time period (assuming the maximum length of time I'd be
encoding is 2 hours, which is pretty safe for my habits). The problem
is, of course, that CBR sucks. So I've just never been happy.
I noticed that mplayer did have the ability to seek in files bigger than
2G when using -forceidx, so at least it has the necessary internal
support to do this. I posed the question to mplayer-dev-eng asking if
it'd be possible to save an index created with -forceidx to an external
file, and use that next time. I got a reply that basically said "it
should be possible, feel free to try." So I did, and it was trivial,
and it works great.
Attached here is the patch I came up with, diffed against mplayer cvs
from a few days ago. It is a quick hack and is not robust, but it does
work. It provides two new options to mplayer: -saveidx and -idxfile.
When both arguments are used, the index file is written to the file
specified after -idxfile and then quits. When just -idxfile is used,
the index file is read. For example:
mplayer file_bigger_than_2g.avi -saveidx -idxfile foo.idx
mplayer file_bigger_than_2g.avi -idxfile foo.idx
This now lets me use constant quantizing with mencoder, so I can get
just about the best quality feasible given the constraints of my CPU, TV
card, and, of course, mpeg4. My tv-startrecord script calls mencoder,
and, when finished, checks the size of the resulting AVI and if it's
bigger than 2G, it will generate an index for it. I have modified
Freevo to check for the existence of foo.avi.idx when playing foo.avi,
and to use it with -idxfile if it exists.
For interest, here is how I call mencoder:
mencoder tv:// -tv
driver=v4l:device=/dev/video0:norm=NTSC:input=1:width=640:height=480:adevice=/dev/dsp:forceaudio:forcechan=2:fps=29.97
-oac mp3lame -lameopts cbr:br=160 -vop crop=620:464:10:4,pp=md -ovc lavc -lavcopts
vcodec=mpeg4:vqmin=2:vqmax=3:keyint=250:v4mv:vlelim=-4:vcelim=9:lumi_mask=0.05:dark_mask=0.05:naq
-o $MOVIEDIR/${starttime}.avi
Notice the use of a deinterlacer (-vop pp=md). I find the median
deinterlacer to be a fair compromise between performance and quality.
Without deinterlacing the video stream, you'll find that your AVIs will
be enormous when using qscale.
So I submit this to the freevo crowd in case some of you find it as
useful as I do.
Happy hacking,
Jason.
--
Jason Tackaberry :: [EMAIL PROTECTED] :: 705-949-2301 x330
Academic Computing Support Specialist
Information Technology Services
Algoma University College :: www.auc.ca
--- main.orig/mplayer.h 2003-04-07 12:03:37.000000000 -0400
+++ main/mplayer.h 2003-10-01 11:34:32.198358336 -0400
@@ -43,6 +43,7 @@
extern int stream_cache_size;
extern int force_ni;
extern int index_mode;
+extern char *index_file;
extern int autosync;
// libmpcodecs:
--- main.orig/cfg-common.h 2003-09-05 20:23:44.000000000 -0400
+++ main/cfg-common.h 2003-10-01 11:39:12.133801680 -0400
@@ -74,6 +74,8 @@
{"noidx", &index_mode, CONF_TYPE_FLAG, 0, -1, 0, NULL},
{"idx", &index_mode, CONF_TYPE_FLAG, 0, -1, 1, NULL},
{"forceidx", &index_mode, CONF_TYPE_FLAG, 0, -1, 2, NULL},
+ {"saveidx", &index_mode, CONF_TYPE_FLAG, 0, -1, 3, NULL},
+ {"idxfile", &index_file, CONF_TYPE_STRING, 0, 0, 0, NULL },
// select audio/videosubtitle stream
{"aid", &audio_id, CONF_TYPE_INT, CONF_RANGE, 0, 8192, NULL},
--- main.orig/libmpdemux/demuxer.h 2003-08-29 04:03:56.000000000 -0400
+++ main/libmpdemux/demuxer.h 2003-10-01 11:34:26.284257416 -0400
@@ -265,6 +265,7 @@
// AVI demuxer params:
extern int index_mode; // -1=untouched 0=don't use index 1=use (geneate) index
+extern char *index_file;
extern int force_ni;
extern int pts_from_bps;
--- main.orig/libmpdemux/demux_avi.c 2003-08-27 18:30:54.000000000 -0400
+++ main/libmpdemux/demux_avi.c 2003-10-01 11:34:12.036423416 -0400
@@ -425,6 +425,7 @@
// AVI demuxer parameters:
int index_mode=-1; // -1=untouched 0=don't use index 1=use (geneate) index
+char *index_file=NULL;
int force_ni=0; // force non-interleaved AVI parsing
void read_avi_header(demuxer_t *demuxer,int index_mode);
--- main.orig/libmpdemux/aviheader.c 2002-11-01 12:46:43.000000000 -0500
+++ main/libmpdemux/aviheader.c 2003-10-01 12:03:40.380594240 -0400
@@ -299,7 +299,22 @@
}
-if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
+if (index_mode != 3 && index_file) {
+ FILE *fp;
+ if ((fp = fopen(index_file, "r")) == NULL) {
+ mp_msg(MSGT_HEADER,MSGL_ERR,"** Can't read index file %s!\n", index_file);
+ return;
+ }
+ int i;
+ fread(&priv->idx_size, sizeof(priv->idx_size), 1, fp);
+ priv->idx=malloc(priv->idx_size*sizeof(AVIINDEXENTRY));
+ for (i=0; i<priv->idx_size;i++) {
+ AVIINDEXENTRY *idx;
+ idx=&((AVIINDEXENTRY *)priv->idx)[i];
+ fread(idx, sizeof(AVIINDEXENTRY), 1, fp);
+ }
+ fclose(fp);
+} else if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
// build index for file:
stream_reset(demuxer->stream);
stream_seek(demuxer->stream,demuxer->movi_start);
@@ -381,8 +396,30 @@
priv->idx_size=priv->idx_pos;
mp_msg(MSGT_HEADER,MSGL_INFO,"AVI: Generated index table for %d
chunks!\n",priv->idx_size);
if(verbose>=2) print_index(priv->idx,priv->idx_size);
-}
+ if (index_mode == 3) {
+ FILE *fp = NULL;
+ unsigned int i=0;
+
+ if (index_file == NULL) {
+ mp_msg(MSGT_HEADER,MSGL_FATAL,"** Specify -idxfile <filename>\n");
+ exit(1);
+ }
+ if ((fp=fopen(index_file, "w")) == NULL) {
+ mp_msg(MSGT_HEADER,MSGL_FATAL,"** Couldn't write index file: %s\n", index_file);
+ exit(1);
+ }
+ fwrite(&priv->idx_size, sizeof(priv->idx_size), 1, fp);
+ for (i=0; i<priv->idx_size; i++) {
+ AVIINDEXENTRY *idx = &((AVIINDEXENTRY *)priv->idx)[i];
+ fwrite(idx, sizeof(AVIINDEXENTRY), 1, fp);
+ }
+ fclose(fp);
+ mp_msg(MSGT_HEADER,MSGL_FATAL,"** Saved index file: %s\n", index_file);
+ exit(1);
+ }
+
+}
}
#undef MIN