View Page Source

Revision (current)
Last Updated by feos on 1/11/2022 11:31 AM
Back to Page

This tool, written by [user:sgrunt] for use in [EncodingGuide/Legacy|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

%%SRC_EMBED c
#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;
}
%%END_EMBED