This tool, written by sgrunt for use in encoding in conjunction with
mencoder
, takes a raw RGB24 video stream on stdin
, removes duplicate frames, and writes the resulting stream to stdout
and the associated timecodes to a specified file.
Usage
Usage is:
dedup <outfile> <fpsnum> <fpsden> <width> <height> [<max consecutive dup frames>]
where:
-
<outfile>
is the time code file to be written; -
<fpsnum>
and<fpsden>
are the numerator and denominator of the frame rate of the input stream; -
<width>
and<height>
are the dimensions of the video stream; and -
<max consecutive dup frames>
is the maximum number of consecutive duplicate frames that will be removed from a stream. If not specified, the default value is 20, which tends to be a good trade off between disk space and usability.
mencoder
can produce a raw RGB24 output with:
mencoder -nosound -of rawvideo -ovc raw -vf format=rgb24,scale <input/output files>
and can read a raw RGB24 input with:
mencoder -demuxer rawvideo -rawvideo format=rgb24:w=<width>:h=<height>:fps=<fps> <input/output/codec settings>
This is best used in conjunction with pipes or FIFOs to avoid having to write large raw files to disk.
Example: logo-combining
mkfifo dedupin mkfifo dedupout mencoder -nosound -of rawvideo -ovc raw -vf format=rgb24,scale logo.avi raw.avi -sub subtitle.srt -subpos 98 -subalign 2 -o dedupin & dedup times.txt <fps> <width> <height> 20 <dedupin >dedupout & mencoder -demuxer rawvideo -rawvideo format=rgb24:w=<width>:h=<height>:fps=<fps> dedupin -ovc x264 -x264encopts crf=0:fullrange=on -sws 9 -o in.avi
(Note that sound will need to be extracted from
raw.avi
and delayed by hand, perhaps with sox
, for encoding purposes.)
Code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
unsigned char *prevframe, *curframe;
unsigned int width = 0, height = 0, framesize = 0;
unsigned int i = 0, tot = 20;
unsigned long framenum = 0;
unsigned short dup = 255;
unsigned long fpsnum = 0, fpsden = 0;
FILE* outfile = 0;
char outfilename[256];
if (argc < 6)
{
fprintf(stderr, "usage: dedup <outfile> <fpsnum> <fpsden> <width> <height> [<max consecutive dup frames>]\n");
exit(1);
}
strncpy(outfilename, argv[1], 256);
fpsnum = atoi(argv[2]);
fpsden = atoi(argv[3]);
width = atoi(argv[4]);
height = atoi(argv[5]);
if (argc >= 7)
{
tot = atoi(argv[6]);
}
framesize = width*height*3;
prevframe = (unsigned char *)malloc(sizeof(unsigned char)*framesize);
if (!prevframe)
{
perror("Couldn't malloc prevframe");
exit(2);
}
curframe = (unsigned char *)malloc(sizeof(unsigned char)*framesize);
if (!curframe)
{
perror("Couldn't malloc prevframe");
free(curframe);
exit(3);
}
outfile = fopen(outfilename, "w");
if (!outfile)
{
perror("Couldn't open output file");
free(prevframe);
free(curframe);
exit(4);
}
fprintf(outfile, "# timecode format v2\n");
while (!feof(stdin))
{
if (fread(curframe, sizeof(unsigned char), framesize, stdin) < framesize)
break;
if (dup != 255)
{
if (!memcmp(prevframe, curframe, framesize))
{
dup = 1;
i++;
if (tot > 0 && i >= tot)
{
dup = 0;
i = 0;
}
}
}
if (!dup || dup == 255)
{
if (fwrite(curframe, sizeof(unsigned char), framesize, stdout) < framesize)
break;
memcpy(prevframe, curframe, framesize);
fprintf(outfile, "%lu.%06lu\n",
framenum*1000*fpsden/fpsnum,
(framenum*10000000000*fpsden/fpsnum+5)/10%1000000);
}
framenum++;
dup = 0;
}
fclose(outfile);
free(prevframe);
free(curframe);
return 0;
}