View unanswered posts    View active topics

All times are UTC - 6 hours





Post new topic Reply to topic  [ 130 posts ] 
Go to page Previous  1 ... 4, 5, 6, 7, 8, 9  Next

Print view Previous topic   Next topic  
Author Message
Search for:
 Post subject:
PostPosted: Thu Aug 18, 2005 7:39 pm 
Offline
Joined: Sun May 15, 2005 8:47 am
Posts: 54
Greg Frost wrote:
If the script isnt too long, you should post it in this thread so that others can benefit too.


I've also modified the commercial_cut for
a) take a -d argument which will unconditionally delete the original file
b) take -c and -s in the mythcommflag format so the arguments from mythcommflag --chanid and --starttime can be passed as it is
c) passed a -n flag so that its nicer, calls usleep(xxx) after couple of writes

and few other changes (insert ignore etc)

Do you want to take a look at the modified commercial_cut.c ?

Thanks
Mudit


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 18, 2005 8:22 pm 
Offline
Joined: Tue Apr 13, 2004 12:41 pm
Posts: 24
I messed up my config somehow, so I used your commercial_cut source but dropped the script and made my own. I just ran a test and it works great!!! Thanks again mwahal and Greg Frost for all of your help. I will post the script in a bit if anyone is interested. Be warned, my first perl script, it's a tad rough around the edges.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 19, 2005 1:52 am 
Offline
Joined: Wed Mar 03, 2004 7:43 pm
Posts: 748
Location: Sydney, Australia
mwahal wrote:
Greg Frost wrote:
If the script isnt too long, you should post it in this thread so that others can benefit too.


I've also modified the commercial_cut for
a) take a -d argument which will unconditionally delete the original file


Having both -k and -d seems a little excessive?

Quote:
Do you want to take a look at the modified commercial_cut.c ?


Yes please, Mudit. Please post here (in a code block)

_________________
| Nigel Pearson, nigel.pearson.au@gmail.com
| "Things you own end up owning you" - Tyler, Fight Club


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 19, 2005 3:00 am 
Offline
Joined: Mon May 10, 2004 8:08 pm
Posts: 1891
Location: Adelaide, Australia
By the way nigel, nice work tidying the code up a bit. I only had a chance to check out your new version recently (trying to help MikeyDIUP).


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 19, 2005 8:25 am 
Offline
Joined: Sun May 15, 2005 8:47 am
Posts: 54
Here is my modified version of commercial_cut.c

Regarding -k and -d, if you make the default behavior that if -k is not specificed, the file will be deleted (without checking with the cutlist), I'm fine with that.

Thanks for a great program !!!
Mudit

Code:
/* ===========================================================================
 * = NAME
 * commercial_cut.c
 *
 * = PURPOSE
 * Slice commercials out of a MythTV MPEG2 recording file.
 * The cuts are nowhere near perfect (i.e. frame accurate),
 * but it seems to work well for Australian DVB recordings
 * and has recently had code added for PVR-250/235 recordings
 * (which also seems to work for files inserted
 *  into MythTV from DVDs via mythcommflag --rebuild).
 *
 * = USAGE
 * commercial_cut -vvv /myth/tv/1005_20050614110000_20050614120000.nuv
 *   or
 * mv /usr/local/bin/mythtranscode /usr/local/bin/mythtranscode.orig
 * cp commercial_cut /usr/local/bin/mythtranscode
 * MythTV->Watch Recordings->{select a recording}->Begin Transcoding
 *
 * = DESCRIPTION
 * Gets the markups (frame number vs byte offset) and cutlist (frame ranges)
 * from the MythTV database, makes a copy of the original file without the
 * cutlist frames in it, adds a minute to the start time, and inserts it back
 * into the database. If there is a cut in the first 25 frames, or if the -k
 * flag is specified, the original file is kept, otherwise 'tis deleted.
 * Running as transcode has its own problems - transcode (or other jobs)
 * deletes entries from the recordedmarkup and recorded tables which
 * correspond to the original recording. In this case, we move the file
 * and table entries to a new start time (one minute before the original).
 *
 * = REVISION
 * $Id: commercial_cut.c 1.5 2005/06/25 13:58:45 nigel Exp $
 *
 * = AUTHORS
 * Greg Frost, Nigel Pearson
 * ========================================================================= */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libgen.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <mysql/mysql.h>

/* This program is normally silent unless an error occurs.    */
/* To see what is happening, verbose output can be enabled.   */
#define output stdout
int verbose = 0;
/* There are three levels of verbosity:
/* The first outputs a few progress type messages.            */
/* The second is for SQL queries or some of the logical steps */
/* The third is for tedious stuff like each file block copied */
#define VERBOSE1(args...) if(verbose)   fprintf(output,args)
#define VERBOSE2(args...) if(verbose>1) fprintf(output,args)
#define VERBOSE3(args...) if(verbose>2) fprintf(output,args)
time_t get_time_t_from_filename_time (char *filename_time);

typedef struct
{
  int frame;
  off_t offset;
  int num_frames;
  off_t size;
} frame_mapping_type;

int mapping_comparison (const void *mm1, const void *mm2)
{
  frame_mapping_type *m1 = (frame_mapping_type *) mm1; 
  frame_mapping_type *m2 = (frame_mapping_type *) mm2; 

  if (m1->frame == m2->frame)
    return 0;
  if (m1->frame < m2->frame)
    return -1;
  else
    return 1;
}

time_t get_time_t_from_database_time (char *database_time)
{
  char time_string[100];
  struct tm time_tm = {0};
  time_t time_time_t;

  strncpy (time_string, database_time, sizeof (time_string));
    
  /* Parse the elements of the time string into a struct tm. */

  if (sscanf (database_time, "%d-%d-%d%*c%d:%d:%d",
         &time_tm.tm_year,
         &time_tm.tm_mon,
         &time_tm.tm_mday,
         &time_tm.tm_hour,
         &time_tm.tm_min,
         &time_tm.tm_sec) != 6)
  {
    fprintf (output, "Error parsing database time '%s'.\n", database_time);
// exit (1);
   return get_time_t_from_filename_time(database_time);
  }

  time_tm.tm_year -= 1900;
  time_tm.tm_mon -= 1;
    
  time_time_t = mktime (&time_tm);

  VERBOSE1("database time %s is %s", database_time, ctime (&time_time_t));

  return time_time_t;
}

time_t get_time_t_from_filename_time (char *filename_time)
{
  struct tm time = {0};

  if (sscanf(filename_time, "%4d%2d%2d%2d%2d%2d",
             &time.tm_year, &time.tm_mon, &time.tm_mday,
             &time.tm_hour, &time.tm_min, &time.tm_sec) != 6)
  {
    fprintf(output, "Error parsing filename time '%s'.\n",filename_time);
    exit(0);
  }

  time.tm_year -= 1900;
  time.tm_mon  -= 1;

  return mktime (&time);
}

char *time_t_to_date_string (time_t time_time_t)
{
  char *date_string;
  struct tm time_tm;
  date_string = malloc (100);

  time_tm = *gmtime (&time_time_t);

  sprintf (date_string, "%04d%02d%02d%02d%02d%02d",
      time_tm.tm_year + 1900,
          time_tm.tm_mon + 1,
          time_tm.tm_mday,
          time_tm.tm_hour,
          time_tm.tm_min,
          time_tm.tm_sec);
  return date_string;
  // yeah its a memory leak, but its easy!
}

int main (int argc, char*argv[])
{
  char input_file_full_path[200];
  char output_file_full_path[200];
  char input_file_name[200];
  int count_loop = 0;
  int chanid = 0;
  int do_usleep = 0;
  int always_delete = 0;
  char start_time[200];
  char end_time[200];
  time_t start_time_t = 0;
  time_t end_time_t;
  time_t new_start_time_t;
  time_t new_end_time_t;
  FILE *input_file;
  FILE *output_file;
  off_t output_file_size;
  off_t seek_to;
  off_t end_of_data;
  char buffer[65536];
  off_t num_to_write;
  int seek_arg;
  int cut_start[2000];
  int cut_end[2000];
  int num_cuts = 0;
  frame_mapping_type mapping[100000];
  frame_mapping_type new_mapping[100000];
  int num_mappings = 0;
  fpos_t file_pos;
  int new_map_index = 0;
  char *title = NULL;
  char *subtitle = NULL;
  char *description = NULL;
  int delete_original = 1;
  int running_as_transcode = 0;
  int experimental_pvr_x50_mode = 0;
  int num_fields;
 
  MYSQL mysql;
  MYSQL_RES *res;
  MYSQL_ROW row;

  /* Make sure that mktime doesnt stuff up because of the timezone.*/

  putenv ("TZ=");

  fprintf (output, "Running Greg Frost's Crude Commercial Cutter\n");

  while (1)
  {
    int optchar;

    optchar = getopt (argc, argv, "TSDcspdlkvn");
   
    if (optchar == -1)
      break;
   
    switch (optchar)
    {
      case 'T':
   VERBOSE1("Title: %s\n", argv[optind]);
    title = argv[optind++];
   break;
       
      case 'S':
   VERBOSE1("Subtitle: %s\n", argv[optind]);
    subtitle = argv[optind++];
     break;
     
      case 'D':
   VERBOSE1("Description: %s\n", argv[optind]);
    description = argv[optind++];
    break;

      case 'c':
   VERBOSE1("Chanid: %s\n", argv[optind]);
    chanid = atoi (argv[optind]);
    optind++;
    break;

      case 's':
     strncpy (start_time, argv[optind], sizeof (start_time));
    optind++;
    start_time_t = get_time_t_from_database_time (start_time);
   VERBOSE1("start time is %s\n", ctime (&start_time_t));
    break;

      case 'p':
   VERBOSE1("Ignoring profile '%s' specification.\n", argv[optind]);
    optind++;
    break;

      case 'd':
   // VERBOSE1("Ignoring -d (not really sure what it does).\n");
   VERBOSE1("forcibly deleted the recording.\n");
   always_delete = 1;
    break;

      case 'l':
   VERBOSE1("Using cutlist (which will be used regardless).\n");
    break;   

      case 'n':
   VERBOSE1("Run commercial_cut nicely, usleep after writes\n");
   do_usleep = 1;
    break;

      case 'k':
   VERBOSE1("Keeping the original recording.\n");
   delete_original = 0;
    break;

      case 'v':
   if (verbose)
          fprintf (output, "Verbosity increased.\n");
   else
     fprintf (output, "Verbose output enabled.\n");
         ++verbose;
    break;   
    }
  }

  if (verbose > 1)
    for (int i = 0; i < argc; i ++)
      fprintf (output, "arg %d = '%s'\n", i, argv[i]);

  /* Does the command name match transcode? */
  if (strcmp(basename(argv[0]), "mythtranscode") == 0)
  {
    running_as_transcode = 1;
    VERBOSE1("Pretending to be mythtranscode!\n");
  }

  // Check that there is either still an unparsed option (the file name)
  // or else the start time and chanid have been specified explicitly.

  if ((optind >= argc) && !(start_time_t && chanid))
  {
    fprintf (output,
      "Usage:\n"
      "\n"
      "./commercial_cut [-T \"Title\"] [-S \"Subtitle\"] [-D \"Description\"]\n"
      "                 [-c chanid -s starttime] [-k] [-v] [-n] [input.nuv]\n"
      "\n"
      "-k    Keep the original file.\n"
      "-n    run nicely, usleep after few writes\n"
      "-v    Verbose. Print extra output about commercial cut's actions.\n"
      "You must either pass a file that is a valid myth recording that can\n"
      "be found in the mythconverg database, or a chanid and starttime of\n"
      "such a recording (this is the format supplied to mythtranscode).\n");
    exit (1);
  }

  mysql_init (&mysql);
 
  if (!mysql_real_connect (&mysql, "localhost", "root", NULL,
              "mythconverg", 0, NULL, 0))
  {
    fprintf (output, "Can't connect to mythconverg MYSQL database\n");
    exit (1);
  }
  else
    VERBOSE2("Connected to the database successfully!\n");

  if (start_time_t && chanid)
  {
    /* Get the end time from the database by queryingthe recorded table. */
    VERBOSE2("Query for end time\n");
 
    //hack more to do.

    sprintf (buffer, "SELECT endtime FROM recorded WHERE chanid = %d AND "
                     "starttime = '%s'", chanid, start_time);
 
    VERBOSE2("%s\n", buffer);
 
    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error querying database!\n");
      exit (1);
    }
    else
      VERBOSE2("Queried the database successfully!\n");   

    res = mysql_use_result (&mysql);
 
    if (!res)
    {
      fprintf (output, "Error using result\n");
      exit (1);
    }
    else
      VERBOSE2("Result with %d fields\n", mysql_field_count (&mysql));

    if (mysql_field_count (&mysql) != 1)
    {
      fprintf (output, "More than one recording returned???\n");
      exit (1);
    }
 
    if (mysql_num_fields (res) != 1)
    {
      fprintf (output, "More than one endtime field returned??\n");
      exit (1);
    }

    row = mysql_fetch_row (res);

    if (!row)
    {
      fprintf (output, "Error getting endtime\n");
      exit (1);
    }
    else
      VERBOSE2("Endtime is:\n%s", row[0]);

    end_time_t = get_time_t_from_database_time (row[0]);

    mysql_free_result (res);
  }
  else
  { 
    strcpy (input_file_full_path, argv[optind]);

    struct stat fs;
    if (stat(input_file_full_path, &fs) == -1)
    {
      VERBOSE1("File %s doesn't exist. Trying in /myth/tv\n", argv[optind]);
      sprintf(input_file_full_path, "/myth/tv/%s", argv[optind]);
      if (stat(input_file_full_path, &fs) == -1)
      {
        fprintf(output, "Error. File [/myth/tv/]%s doesn't exist.\n",
                argv[optind]);
        exit(-1);
      }
    }

    /* Extract the channel id and the start and end time from the name of */
    /* the recording nuv file. */

    strncpy (input_file_name, basename (input_file_full_path),
            sizeof (input_file_name));

    if (sscanf (input_file_name,
                "%d_%14s_%14s.nuv", &chanid, start_time, end_time) != 3)
    {
      fprintf (output, "Error getting channel-id_start-time_end-time\n");
      fprintf (output, "      from file name %s\n", input_file_name);
      exit (1);
    }

    /* Parse the start and end times into a time_t */
    start_time_t = get_time_t_from_filename_time(start_time);
    end_time_t   = get_time_t_from_filename_time(end_time);
  }
 
  VERBOSE1("The start time is %s", ctime (&start_time_t));
  VERBOSE1("The end   time is %s", ctime (&end_time_t));

  /* Attempt to adjust a transcode entry in the jobqueue to indicate that */
  /* The transcode is now running. */

  sprintf (buffer,
       "UPDATE jobqueue SET status=4 where chanid=%d and starttime=%s "
       "and type=1",
      chanid, time_t_to_date_string (start_time_t));
        
  VERBOSE2("%s\n", buffer);

  if (mysql_real_query (&mysql, buffer, strlen(buffer)))
  {
    fprintf (output, "Error altering jobqueue status to running!\n");
    exit (1);
  }
  else
    VERBOSE1("set jobqueue status to running\n");   

  sprintf (input_file_full_path, "/myth/tv/%d_%s_%s.nuv", chanid,
        time_t_to_date_string (start_time_t),
        time_t_to_date_string (end_time_t));

  sprintf (output_file_full_path, "/myth/tv/%d_%s_%s.nuv.tmp",
        chanid,
        time_t_to_date_string (start_time_t),
        time_t_to_date_string (end_time_t));

  VERBOSE1("Input File Full Path: %s\n"
           "Output File Full Path: %s\n",
           input_file_full_path, output_file_full_path);

  sprintf (buffer, "SELECT cutlist FROM recorded WHERE chanid = %d AND "
                   "starttime = '%s'", chanid, start_time);
 
  VERBOSE2("%s\n", buffer);
 
  if (mysql_real_query (&mysql, buffer, strlen(buffer)))
  {
    fprintf (output, "Error querying database!\n");
    exit (1);
  }
  else
    VERBOSE2("Queried the database successfully!\n");   

  res = mysql_use_result (&mysql);
 
  if (!res)
  {
    fprintf (output, "Error using result\n");
    exit (1);
  }
  else
    VERBOSE2("Result with %d fields\n", mysql_field_count (&mysql));

  if (mysql_field_count (&mysql) != 1)
  {
    fprintf (output, "More than one recording returned???\n");
    exit (1);
  }
 
  if (mysql_num_fields (res) != 1)
  {
    fprintf (output, "More than one cutlist field returned??\n");
    exit (1);
  }

  row = mysql_fetch_row (res);

  if (!row)
  {
    fprintf (output, "Error getting cutlist\n");
    exit (1);
  }
  else
    VERBOSE1("Cutlist is:\n%s", row[0]);

  /* Parse the cutlist to get the start and end sections. */

  {
    char *s = row[0];
    char *line;
    while (line = strtok (s, "\n"))
    {
      s = NULL;
      if (sscanf (line, "%d - %d", &cut_start[num_cuts],
              &cut_end[num_cuts]) != 2)
      {
        fprintf (output, "Error Parsing Cutlist\n");
   exit (1);
      }
      num_cuts++;
    }
  }

  /* If there is at least one cut, and the first cut is non-zero and */
  /* less than 25 (i.e a delete after right near the start of the */
  /* recording) then keep the original recording. */
 
  if (!always_delete && (num_cuts > 0) && (cut_start[0] > 0) && (cut_start[0] < 25))
  {
    delete_original = 0;
    cut_start[0] = 0;
  }

  if (delete_original)
    VERBOSE1("Will delete the original recording\n");
  else
    VERBOSE1("Will keep the original recording\n");

  if (verbose)
    for (int cut = 0; cut < num_cuts; cut++)
      fprintf(output, "Cutlist %d: %d - %d\n",
              cut, cut_start[cut], cut_end[cut]);

  mysql_free_result (res);

  /* Now get the information from the recordedmarkup for the frame */
  /* file offset mappings. */

  sprintf (buffer, "SELECT mark,offset FROM recordedmarkup WHERE chanid = %d AND "
                   "starttime = '%s' AND type=9", chanid, start_time);
 
  VERBOSE2("%s\n", buffer);
 
  if (mysql_real_query (&mysql, buffer, strlen(buffer)))
  {
    fprintf (output, "Error querying database!\n");
    exit (1);
  }
  else
    VERBOSE2("Queried the database successfully!\n");   

  res = mysql_use_result (&mysql);
 
  if (!res)
  {
    fprintf (output, "Error using result\n");
    exit (1);
  }
  else
    VERBOSE2("Result with %d fields\n", mysql_field_count (&mysql));

  row = mysql_fetch_row (res);

  if (!row)
  {
    VERBOSE1("No type 9 entries in the database. Entering experimental PVR-x50 mode\n");
    experimental_pvr_x50_mode = 1;
    mysql_free_result (res);

    sprintf (buffer, "SELECT mark,offset FROM recordedmarkup WHERE chanid = %d AND "
                     "starttime = '%s' AND type=6", chanid, start_time);
 
    VERBOSE2("%s\n", buffer);
 
    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error querying database!\n");
      exit (1);
    }
    else
      VERBOSE2("Queried the database successfully!\n");   

    res = mysql_use_result (&mysql);
 
    if (!res)
    {
      fprintf (output, "Error using result\n");
      exit (1);
    }
    else
      VERBOSE2("Result with %d fields\n", mysql_field_count (&mysql));

    row = mysql_fetch_row (res);

    if (!row)
    {
   fprintf (output, "No rows in recordedmarkup of type 6 or type 9. I'm, going to have to give up!\n");
   exit (1);
    }
  }

  do
  {
    VERBOSE3("%s %s\n", row[0], row[1]);
   
    if (sscanf (row[0], "%d", &mapping[num_mappings].frame) != 1)
    {
      fprintf (output, "error parsing frame from frame mapping %d\n",
               num_mappings);
      exit (1);
    }
     
    if (sscanf (row[1], "%lld", &mapping[num_mappings].offset) != 1)
    {
      fprintf (output, "error parsing offset from frame mapping %d\n",
               num_mappings);
      exit (1);
    }
     
    num_mappings++;
  } while (row = mysql_fetch_row (res));

  mysql_free_result (res);

  if (experimental_pvr_x50_mode)
  {
    for (int map = 0; map < num_mappings; map++)
   mapping[map].frame *= 12;
  }

  qsort (mapping, num_mappings, sizeof (mapping[0]), mapping_comparison);

  /* Determine the number of frames and size of each mapping. */

  for (int map = 0; map < num_mappings - 1; map++)
  {
    mapping[map].num_frames =  mapping[map + 1].frame - mapping[map].frame,
    mapping[map].size = mapping[map + 1].offset - mapping[map].offset;
  }

  /* Determine the size of the last mapping using the file size. */

  mapping[num_mappings - 1].num_frames = 0;
  {
    struct stat file_stats;
    int stat_return;
    if (stat (input_file_full_path, &file_stats))
    {
      fprintf (output, "Cannot stat file %s\n", input_file_full_path);
      exit (1);
    }
    mapping[num_mappings - 1].size = file_stats.st_size;
  }
 
  VERBOSE1("file size is %lld\n", mapping[num_mappings - 1].size);
  mapping[num_mappings - 1].size =
    mapping[num_mappings - 1].size - mapping[num_mappings - 1].offset;

  if (verbose>2)
    for (int map = 0; map < num_mappings; map++)
    {
      fprintf (output, "mapping %d: %d %lld size %d %lld\n",
               map,
               mapping[map].frame,
               mapping[map].offset,
               mapping[map].num_frames,
               mapping[map].size);
    }

  /* Now, copy one file to the next whilst cutting out the commercials */
  /* and producing a set of mappings.                                  */

  input_file = fopen (input_file_full_path, "r");
  if (!input_file)
  {
    fprintf (output, "Error opening file %s\n", input_file_full_path);
    exit (1);
  }

  output_file = fopen (output_file_full_path, "w");
  if (!output_file)
  {
    fprintf (output, "Error opening output file %s\n", output_file_full_path);
    exit (1);
  }

  /* The list of type 6 mappings I was given to examine had the */
  /* offset for frame zero at 38. I don't know what these first */
  /* 38 bytes are, but I'll copy them to the new file anyway. */

  /* We need to read up to the first offset otherwise all of */
  /* the seeks will be wrong! It should not do any harm to do */
  /* this for DVB fince the first offset should be zero. */

  {
    int num_bytes_to_copy = mapping[0].offset;
    count_loop = 0;

   while (num_bytes_to_copy != 0)
        {
          int num_this_time;
   
          if (num_bytes_to_copy < sizeof (buffer))
            num_this_time = num_bytes_to_copy;
          else
            num_this_time = sizeof (buffer);
     
          fread (buffer, num_this_time, 1, input_file);
          fwrite (buffer, num_this_time, 1, output_file);
     count_loop++;
     if (do_usleep && count_loop % 5 == 0) usleep(1000);
          num_bytes_to_copy -= num_this_time;
        }
     VERBOSE2("loops in first count = %d\n", count_loop);
  }

  {
    int map_index = 0;
    off_t num_bytes_to_copy;
    count_loop = 0;

    /* For each cut, copy up to the start of the cut and then seek past */
    /* the cut portion */
    for (int cut = 0; cut <= num_cuts; cut++)
    {
      num_bytes_to_copy = 0;
     
      while (map_index < num_mappings &&
             ((cut == num_cuts) ||
              ((mapping[map_index].frame + mapping[map_index].num_frames) <
               cut_start[cut])))
      {
        new_mapping[new_map_index].num_frames = mapping[map_index].num_frames;
        new_mapping[new_map_index].size = mapping[map_index].size;

         num_bytes_to_copy = mapping[map_index].size;
     
        VERBOSE3("Copying %lld bytes from %lld\n",
                 num_bytes_to_copy, mapping[map_index].offset);

   while (num_bytes_to_copy != 0)
        {
          int num_this_time;
   
          if (num_bytes_to_copy < sizeof (buffer))
            num_this_time = num_bytes_to_copy;
          else
            num_this_time = sizeof (buffer);
     
          fread (buffer, num_this_time, 1, input_file);
          fwrite (buffer, num_this_time, 1, output_file);
     count_loop++;
     if (do_usleep && count_loop % 5 == 0) usleep(1000);
          num_bytes_to_copy -= num_this_time;
        }

   map_index++;
   new_map_index++;
      }
     

      /* Now skip data until we have passed the cut point. */

      while (map_index < num_mappings &&
             ((cut == num_cuts) || (mapping[map_index].frame <= cut_end[cut])))
      {
   /* Skip the data we do not wish to copy. */

   VERBOSE3("skipping %d: %d frames %lld bytes",
                 map_index,
                 mapping[map_index].num_frames,
                 mapping[map_index].size);
   VERBOSE3(" from frame %d offset %lld\n",
                 mapping[map_index].frame,
                 mapping[map_index].offset);

   if (fseek (input_file, mapping[map_index].size, SEEK_CUR))
   {
     fprintf (output, "Error seeking input file ahead %lld\n",
         mapping[map_index].size);
     exit (1);
   }

   map_index++;
      }     
    }     
    VERBOSE2("loops in second count = %d\n", count_loop);
  }

  fclose (input_file);
  fclose (output_file);

  VERBOSE2("closed input and output files\n");

  /* Determine the size of the output file. */
 
  {
    struct stat file_stats;
    if (stat (output_file_full_path, &file_stats))
    {
      fprintf (output, "Cannot stat file %s\n", output_file_full_path);
      exit (1);
    }
    output_file_size = file_stats.st_size;
  }

  VERBOSE1("Output file size %lld\n", output_file_size);

  /* Calculate a new start time so that we can enter the new */
  /* mapping info into the database (without clashing with the */
  /* existing cut info. */

  new_start_time_t = start_time_t;

  do
  {
    if (new_start_time_t != start_time_t)
      VERBOSE1("start time %s already in database!???\n",
               time_t_to_date_string (new_start_time_t));

    new_start_time_t = new_start_time_t + 60;

    sprintf (buffer,
           "SELECT * FROM recorded WHERE chanid = %d AND starttime = '%s'",
           chanid, time_t_to_date_string (new_start_time_t));

    VERBOSE2("%s\n", buffer);
         
    if (mysql_real_query (&mysql, buffer, strlen(buffer)) != 0)
    {
      fprintf (output, "Error querying for existing entry\n");
      exit (1);
    }

    res = mysql_use_result (&mysql); 
    row = mysql_fetch_row (res);
    mysql_free_result (res);
 
    if (!row)
      break;
  } while (1);
 
  VERBOSE1("new start time %s", ctime (&new_start_time_t));

  /* Now calculate the new recordedmarkup info. */
 
  for (int map_index = 0; map_index < new_map_index; map_index++)
  {
    if (map_index == 0)
    {
      new_mapping[map_index].frame = 0;
      new_mapping[map_index].offset = 0;
    }
    else
    {
      new_mapping[map_index].frame =
        new_mapping[map_index - 1].frame +
        new_mapping[map_index - 1].num_frames;
      new_mapping[map_index].offset =
        new_mapping[map_index - 1].offset +
        new_mapping[map_index - 1].size;
    }
  }

  if (experimental_pvr_x50_mode)
  {
    for (int map_index = 0; map_index < new_map_index; map_index++)
      new_mapping[map_index].frame /= 12;
  }

  /* Now insert the new recordedmarkup information into the database. */
 
  for (int map_index = 0; map_index < new_map_index; map_index++)
  {
    sprintf (buffer,
            "INSERT IGNORE INTO recordedmarkup VALUES (%d,'%s',%d,'%lld',%d)",
        chanid, time_t_to_date_string (new_start_time_t),
        new_mapping[map_index].frame,
        new_mapping[map_index].offset,
        experimental_pvr_x50_mode ? 6 : 9);
        
    VERBOSE3("new map %d: %s", map_index, buffer);

    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error entering recordedmarkup into database!\n");
      exit (1);
    }
    else
      VERBOSE3("Entered recordedmarkup into db successfully!\n");   
  }
 
  /* Create a new end time based on the number of frames in */
  /* the cut recording. */

  new_end_time_t =
    new_start_time_t + new_mapping[new_map_index - 1].frame *
    (experimental_pvr_x50_mode ? 12 : 1) / 25 / 60 * 60 + 60;
 
  VERBOSE1("new end time %s", ctime (&new_end_time_t));

  /* Get all of the info from the original recording so we can */
  /* write a new entry to the database. */

  sprintf (buffer, "SELECT * FROM recorded WHERE chanid = %d AND "
                   "starttime = '%s'", chanid, start_time);
  VERBOSE2("%s\n", buffer);
 
  if (mysql_real_query (&mysql, buffer, strlen(buffer)))
  {
    fprintf (output, "Error querying database!\n");
    exit (1);
  }
  else
  {
    VERBOSE2("Queried the database successfully!\n");   
  }

  res = mysql_use_result (&mysql);
 
  if (!res)
  {
    fprintf (output, "Error using result[A\n");
    exit (1);
  }
  else
  {
    num_fields = mysql_field_count (&mysql);
    VERBOSE2("Result with %d fields\n", num_fields);
  }

  if (num_fields != 25)
  {
    fprintf (output, "Expected 25 fields in recorded got %d\n", num_fields);
    // 0.16 had 22 fields (up to originalairdate)
    // 0.17 and 0.18 have 25 fields (up to deletepending)
    fprintf (output, "DB newer than 0.18. This may cause problems?\n");
  }

  row = mysql_fetch_row (res);

  {
    char *escaped_title;
    char *escaped_subtitle;
    char *escaped_description;
 
    if (!title)
      title = row[3];
    if (!subtitle)
      subtitle = row[4];
    if (!description)
      description = row[5];

    escaped_title = calloc (strlen (title) * 3, 1);
    escaped_subtitle = calloc (strlen (subtitle) * 3, 1);
    escaped_description = calloc (strlen (description) * 3, 1);

    mysql_real_escape_string (
      &mysql, escaped_title, title, strlen (title));
    mysql_real_escape_string (
      &mysql, escaped_subtitle, subtitle, strlen (subtitle));
    mysql_real_escape_string (
      &mysql, escaped_description, description, strlen (description));


    sprintf (buffer,"INSERT IGNORE INTO recorded VALUES (%s,'%s','%s','%s','%s','%s',",
             row[0],       // chanid
             time_t_to_date_string (new_start_time_t),
             time_t_to_date_string (new_end_time_t),
             escaped_title,
             escaped_subtitle,
             escaped_description);

    sprintf (buffer+strlen(buffer), "'%s','%s',NULL,%s,'',%s,%s,'%s',",
             row[6],      // category
             row[7],      // hostname
             row[9],      // editing
             row[11],      // autoexpire
             row[12],      // commflagged
             row[13]);      // recgroup

    if (!row[14])
      row[14] = "0";

    sprintf (buffer+strlen(buffer), "%d,'%s','%s',%s,%lld,%s,%s",
             atoi(row[14]) + 1,   // recordid
             row[15],      // seriesid
             row[16],      // programid
             row[17],      // lastmodified
             output_file_size,
             row[19],      // stars
             row[20]);      // previouslyshown

    for (int field = 21; field < num_fields; ++field)
    {
      VERBOSE2("Adding field %d - %s\n", field, row[field]);
      sprintf (buffer+strlen(buffer), ",'%s'", row[field]);
    }

    strcat(buffer+strlen(buffer), ")");
  }

  mysql_free_result (res);
     
  VERBOSE2("%s\n", buffer);

  if (mysql_real_query (&mysql, buffer, strlen(buffer)))
  {
    fprintf (output, "Error querying database!\n");
    exit (1);
  }
  else
    VERBOSE2("Queried the database successfully!\n");   

  /* Rename the temporary file so that it matches the new start and end times. */

  {
    char new_output_name[200];
    sprintf (new_output_name, "/myth/tv/%d_%s_%s.nuv", chanid,
        time_t_to_date_string (new_start_time_t),
        time_t_to_date_string (new_end_time_t));
    if (rename (output_file_full_path, new_output_name))
    {
      fprintf (output, "error renaming %s to %s\n",
                output_file_full_path, new_output_name);
      exit (1);
    }
  }

  if (delete_original)
  {
    /* Remove the original recording from the database and the file */
    VERBOSE1("deleting original\n");

    if (unlink (input_file_full_path))
      fprintf (output, "error deleting %s\n", input_file_full_path);
    else
      VERBOSE1("deleted %s\n", input_file_full_path);

    sprintf (buffer,
            "DELETE FROM recorded where chanid=%d and starttime=%s",
        chanid, time_t_to_date_string (start_time_t));
        
    VERBOSE2("%s\n", buffer);

    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error deleting original recorded!\n");
      exit (1);
    }
    else
      VERBOSE2("Deleted original recorded successfully\n");   

    sprintf (buffer,
            "DELETE FROM recordedmarkup where chanid=%d and starttime=%s",
        chanid, time_t_to_date_string (start_time_t));
        
    VERBOSE2("%s\n", buffer);

    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error deleting original recordedmarkup!\n");
      exit (1);
    }
    else
      VERBOSE2("Deleted original recordedmarkup successfully\n");   
  }

  if (running_as_transcode && !delete_original)
  {
    VERBOSE1("attempting to do what is needed to keep original\n");

    /* Find a new unique time for the recording in the past. */
   
    /* This needs to be done because for some reason, myth deletes the */
    /* recordedmarkup and the recording when the transcode job completes. */
       
    new_start_time_t = start_time_t;

    do
    {
      if (new_start_time_t != start_time_t)
        fprintf (output, "start time %s already in database!\n",
                 time_t_to_date_string (new_start_time_t));

      new_start_time_t = new_start_time_t - 60;

      sprintf (buffer,
             "SELECT * FROM recorded WHERE chanid = %d AND starttime = '%s'",
             chanid, time_t_to_date_string (new_start_time_t));

      VERBOSE2("%s\n", buffer);
         
      if (mysql_real_query (&mysql, buffer, strlen(buffer)) != 0)
      {
        fprintf (output, "Error querying for existing entry\n");
        exit (1);
      }

      res = mysql_use_result (&mysql); 
      row = mysql_fetch_row (res);
      mysql_free_result (res);
 
      if (!row)
        break;
    } while (1);
 
    VERBOSE1("new start time %s", ctime (&new_start_time_t));

    sprintf (output_file_full_path, "/myth/tv/%d_%s_%s.nuv",
            chanid, time_t_to_date_string (new_start_time_t),
            time_t_to_date_string (end_time_t));

    if (rename (input_file_full_path, output_file_full_path))
    {
      fprintf (output, "error renaming %s to %s\n",
                input_file_full_path, output_file_full_path);
      exit (1);
    }
    else
      VERBOSE1("renamed %s to %s\n",
               input_file_full_path, output_file_full_path);

    sprintf (
      buffer,
      "UPDATE recorded SET starttime=%s where chanid=%d and starttime=%s",
      time_t_to_date_string (new_start_time_t),
      chanid, time_t_to_date_string (start_time_t));
        
    VERBOSE2("%s\n", buffer);

    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error changing the recording start time!\n");
      exit (1);
    }
    else
      VERBOSE2("changed the recording start time.\n");   

    sprintf (
      buffer,
      "UPDATE recordedmarkup SET starttime=%s where chanid=%d and starttime=%s",
      time_t_to_date_string (new_start_time_t),
      chanid, time_t_to_date_string (start_time_t));
        
    VERBOSE2("%s\n", buffer);

    if (mysql_real_query (&mysql, buffer, strlen(buffer)))
    {
      fprintf (output, "Error changing the recordedmarkup start time!\n");
      exit (1);
    }
    else
      VERBOSE2("changed the recordedmarkup start time.\n");   
  }

  /* Update the jobqueue to indicate the job is now complete. */
     
  sprintf (buffer,
       "UPDATE jobqueue SET status=5 where chanid=%d and starttime=%s "
       "and type=1",
      chanid, time_t_to_date_string (start_time_t));
        
  VERBOSE2("%s\n", buffer);

  if (mysql_real_query (&mysql, buffer, strlen(buffer)))
  {
    fprintf (output, "Error setting jobqueue status to stopped!\n");
    exit (1);
  }
  else
    VERBOSE1("jobqueue set to stopped.\n");   

  exit (0);
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 19, 2005 8:27 am 
Offline
Joined: Sun May 15, 2005 8:47 am
Posts: 54
And here is my modified mythcommflag. I've moved the original to mythcommflag.orig file. I'm sure a user job can achieve same thing but I was too lazy to find out how user job works.

Code:
#!/bin/csh -f

set path=($path ~mythtv/bin)
set rec="/myth/tv/mcf.rec"
echo " " >> $rec
echo starting at `date` >> $rec
echo -n "Arguments passed "  >> $rec
set myvars=($*)
echo "$myvars" >> $rec
set skip=`echo $myvars | grep skip`
set myvars=`echo $myvars | sed -e 's/-skip//'`
if ($#skip == 0) then
   /usr/bin/nice -n 0 mythcommflag.orig $myvars >> &$rec
else
   echo skipping mythcommflag.orig $myvars >> &$rec
endif
sudo /usr/bin/nice --adjustment=-10 mythcommflag.orig $myvars --gencutlist >> &$rec
set rc=$status
set comcut=`echo $myvars | sed -e 's/^.*--chanid/-c/' -e 's/-starttime/s/' -e 's/--.*$//'`
~mythtv/bin/commercial_cut -n -vv -d $comcut >> &$rec
echo finished at `date` >> $rec
exit $rc


Top
 Profile  
 
PostPosted: Mon Aug 22, 2005 4:37 am 
Offline
Joined: Mon Aug 22, 2005 4:32 am
Posts: 1
greg frost, and others, have someone looking to use two streams of video, one with dvb another an in house advertising loop, when ads appear on the dvb signal it cuts to inhouse advertising loop and when ads finished back to dvb telecast. ever heard of this being done, doesnt matter if dvb delayed to allow for processing. maybe financing available if crude version can be presented


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 9:18 pm 
Offline
Joined: Wed Mar 03, 2004 7:43 pm
Posts: 748
Location: Sydney, Australia
mwahal wrote:
Here is my modified version of commercial_cut.c

Regarding -k and -d, if you make the default behavior that if -k is not specificed, the file will be deleted


I just checked v0.5 and deletion is the default behaviour. Line 181 says:
Code:
  int delete_original = 1;


Was it not deleting it by default for you?[/b]

_________________
| Nigel Pearson, nigel.pearson.au@gmail.com
| "Things you own end up owning you" - Tyler, Fight Club


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 9:22 pm 
Offline
Joined: Wed Mar 03, 2004 7:43 pm
Posts: 748
Location: Sydney, Australia
electrophile, interesting commercial replacement idea. I have not heard of it being done. The hardest part is detecting the ad breaks accurately. I think editing live streams is also difficult.

Sadly, I don't have the time (or skills) to do this.

_________________
| Nigel Pearson, nigel.pearson.au@gmail.com
| "Things you own end up owning you" - Tyler, Fight Club


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 9:29 pm 
Offline
Joined: Sun May 15, 2005 8:47 am
Posts: 54
nigelpearson wrote:
mwahal wrote:
Here is my modified version of commercial_cut.c

Regarding -k and -d, if you make the default behavior that if -k is not specificed, the file will be deleted


I just checked v0.5 and deletion is the default behaviour. Line 181 says:
Code:
  int delete_original = 1;


Was it not deleting it by default for you?[/b]


if
(num_cuts > 0) && (cut_start[0] > 0) && (cut_start[0] < 25))

was true, the delete_original gets reset to 0.

since it is still relying on the cutpoints. I want it to unconditionally delete no matter where the cut point is present.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 9:39 pm 
Offline
Joined: Mon May 10, 2004 8:08 pm
Posts: 1891
Location: Adelaide, Australia
nigelpearson wrote:
electrophile, interesting commercial replacement idea. I have not heard of it being done. The hardest part is detecting the ad breaks accurately. I think editing live streams is also difficult.

Sadly, I don't have the time (or skills) to do this.


I'm in the same boat as nigel, but I can see that it would be a nice feature to have in myth. I'd like to be able to watch live tv, and then when there was a commercial break, have it automatically switch to playing back a recording, then when the commercial break ends switch back to live tv.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 9:43 pm 
Offline
Joined: Mon May 10, 2004 8:08 pm
Posts: 1891
Location: Adelaide, Australia
mwahal wrote:
if (num_cuts > 0) && (cut_start[0] > 0) && (cut_start[0] < 25))

was true, the delete_original gets reset to 0.

since it is still relying on the cutpoints. I want it to unconditionally delete no matter where the cut point is present.

This should only occur if you wanted to keep less than 25 frames from the start of the recording and then delete frames thereafter. I cant see anyone doing this deliberately. Notice that cut_start[0] needs to be > 0 not just equal to zero. If you are just chopping less than 25 frames off the start (which I could see someone wanting to do), it wont change the behaviour because cut_start[0] would be 0.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 9:49 pm 
Offline
Joined: Sun May 15, 2005 8:47 am
Posts: 54
Greg Frost wrote:
mwahal wrote:
if (num_cuts > 0) && (cut_start[0] > 0) && (cut_start[0] < 25))

was true, the delete_original gets reset to 0.

since it is still relying on the cutpoints. I want it to unconditionally delete no matter where the cut point is present.

This should only occur if you wanted to keep less than 25 frames from the start of the recording and then delete frames thereafter. I cant see anyone doing this deliberately. Notice that cut_start[0] needs to be > 0 not just equal to zero. If you are just chopping less than 25 frames off the start (which I could see someone wanting to do), it wont change the behaviour because cut_start[0] would be 0.


Greg,

I do understand the logic. But in my HDTV programs I recorded in mpeg2-ts format, after it ran thru mythcommflag and mythcommflag --gencutlist option, I did find that somehow I had both original and the new commercial cut copy of the program.

Blame it on buggy mythcommflag or whatever. I had to get rid of this checking in order not to have double copy of each program.

I never load the cutpoints manual or ever edit them by hand. I let the mythcommflag do its magic and let commercial cut sew back the file. I'm 99% satisfied by the job.

thanks
mudit


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 27, 2005 9:59 pm 
Offline
Joined: Wed Mar 03, 2004 7:43 pm
Posts: 748
Location: Sydney, Australia
Mudit, I have made a version 0.6 (on the Wiki) which:

1) Includes your -n (nice) argument. I added code to do the equivalent of a "nice commercial_cut" also, so not only will it sleep, but the little CPU processing it does will be only done in idle time

2) Includes your "always delete" option (but with a -x argument, as I think -d was already taken by mythtranscode)

3) Processes a .rc file, ~/.commercial_cut.rc, for extra arguments. Put something like -v -n and -x in that file and you won't have to ever specify them on the command line.

I think I also have the other (-c -s) change, but I am not 100% sure (I didn't test that).

_________________
| Nigel Pearson, nigel.pearson.au@gmail.com
| "Things you own end up owning you" - Tyler, Fight Club


Top
 Profile  
 
PostPosted: Fri Sep 09, 2005 5:44 am 
Offline
Joined: Fri Sep 09, 2005 5:11 am
Posts: 1
Sorry to reply to old posts, but I hope this is worth the inconveinience...

stdim wrote:
My problem is that I cannot download it....
....even if I go to (Attachments) links...
The name is : commercial_cut-0.1.tar.gz


Greg Frost wrote:
I do not know what happened to the attachments on the wiki.


Xsecrets wrote:
yeah sorry some of the attachments from the wiki got lost a while back.


Heya. I found a cached page on a search engine that listed the "attachments" for the files, and then edited the wiki pages on this page to point to the files using the ![internal://] naming convention. Let's see if it stays. :-D

Thanks for making this software Mr. Frost. It took a little time, but I modified it (0.6) to work on my Debian system (local build of myth-0.18.1.) With a little more work, I think it should be possible to build a general purpose version that will work on the knoppix system (default) or others systems (with mods to a config.) If you are interrested in any changes or a unified diff from your 0.6 version, I'll try to check back and see your opinion. :-)

Combining this with automagic scripting and mencoder will afford me the great fun of automagical video compression and service without the numerous memory/swap problems found in cvs ffmpeg and the raw video export of mythtranscode using names pipes for audio and video. (Yes, mencoder may not be as fast as it is said that ffmpeg can be, but it works much better than the present cvs ffmpeg on a memory-limited system.)

You kick ASCII! Thanks for your work on this!

Also, to the people that suggested avidemux/avidemux2 great programs.

And the suggestions on using the myth edit were great!

Thanks to you all!
(Good thread.)


Top
 Profile  
 

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 130 posts ] 
Go to page Previous  1 ... 4, 5, 6, 7, 8, 9  Next



All times are UTC - 6 hours




Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group

Theme Created By ceyhansuyu