Ticket #10793: mythcommflag.patch

File mythcommflag.patch, 84.5 KB (added by bryan@…, 6 years ago)

Changes to Logo Detection, Scene Change Detection, and Heurisitic scoring (all in one)

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 9439d39..3c95424 100644
    a b void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc, 
    13721372            }
    13731373
    13741374            if (FlagIsSet(kDecodeLowRes))
    1375                 enc->lowres = 2; // 1 = 1/2 size, 2 = 1/4 size
     1375            {
     1376                if (enc->height > 720)
     1377                    enc->lowres = 2; // 2 = 1/4 size
     1378                else
     1379                    enc->lowres = 1; // 1 = 1/2 size
     1380            }
    13761381        }
    13771382        else if (CODEC_ID_H264 == codec->id)
    13781383        {
  • mythtv/programs/mythcommflag/ClassicCommDetector.cpp

    diff --git a/mythtv/programs/mythcommflag/ClassicCommDetector.cpp b/mythtv/programs/mythcommflag/ClassicCommDetector.cpp
    index 800e83d..bb83323 100644
    a b ClassicCommDetector::ClassicCommDetector(SkipType commDetectMethod_in, 
    134134    width(0),                                  height(0),
    135135    horizSpacing(0),                           vertSpacing(0),
    136136    fpm(0.0),                                  blankFramesOnly(false),
    137     blankFrameCount(0),                        currentAspect(0),
     137    blankFrameCount(0),                       
     138    currentAspect(0),                          colMax(NULL),
    138139    totalMinBrightness(0),                     detectBlankFrames(false),
    139140    detectSceneChanges(false),                 detectStationLogo(false),
    140141    logoInfoAvailable(false),                  logoDetector(0),
    141     framePtr(0),                               frameIsBlank(false),
    142     sceneHasChanged(false),                    stationLogoPresent(false),
     142    framePtr(0),                               sceneHasChanged(false),
    143143    lastFrameWasBlank(false),                  lastFrameWasSceneChange(false),
    144144    decoderFoundAspectChanges(false),          sceneChangeDetector(0),
    145145    player(player_in),
    ClassicCommDetector::ClassicCommDetector(SkipType commDetectMethod_in, 
    152152    preRoll(0),                                postRoll(0)
    153153{
    154154    commDetectBorder =
    155         gCoreContext->GetNumSetting("CommDetectBorder", 20);
     155        gCoreContext->GetNumSetting("CommDetectBorder", 5);
    156156    commDetectBlankFrameMaxDiff =
    157157        gCoreContext->GetNumSetting("CommDetectBlankFrameMaxDiff", 25);
    158158    commDetectDarkBrightness =
    void ClassicCommDetector::Init() 
    206206            .arg(width).arg(height)
    207207            .arg(player->GetFrameRate()).arg(commDetectMethod));
    208208
    209     if ((width * height) > 1000000)
    210     {
    211         horizSpacing = 10;
    212         vertSpacing = 10;
    213     }
    214     else if ((width * height) > 800000)
    215     {
    216         horizSpacing = 8;
    217         vertSpacing = 8;
    218     }
    219     else if ((width * height) > 400000)
    220     {
    221         horizSpacing = 6;
    222         vertSpacing = 6;
    223     }
    224     else if ((width * height) > 300000)
    225     {
    226         horizSpacing = 6;
    227         vertSpacing = 4;
    228     }
    229     else
    230     {
    231         horizSpacing = 4;
    232         vertSpacing = 4;
    233     }
     209    horizSpacing = 1;
     210    vertSpacing = 1;
    234211
    235212    LOG(VB_COMMFLAG, LOG_INFO,
    236213        QString("Using Sample Spacing of %1 horizontal & %2 vertical pixels.")
    void ClassicCommDetector::Init() 
    245222    decoderFoundAspectChanges = false;
    246223
    247224    lastSentCommBreakMap.clear();
     225   
     226    colMax = new unsigned char[width];
    248227
    249228    // Check if close to 4:3
    250229    if (fabs(((width*1.0)/height) - 1.333333) < 0.1)
    251230        currentAspect = COMM_ASPECT_NORMAL;
    252231
    253232    sceneChangeDetector = new ClassicSceneChangeDetector(width, height,
    254         commDetectBorder, horizSpacing, vertSpacing);
     233        commDetectBorder, fps);
    255234    connect(
    256235         sceneChangeDetector,
    257236         SIGNAL(haveNewInformation(unsigned int,bool,float)),
    void ClassicCommDetector::Init() 
    259238         SLOT(sceneChangeDetectorHasNewInformation(unsigned int,bool,float))
    260239    );
    261240
    262     frameIsBlank = false;
    263     stationLogoPresent = false;
    264 
    265241    framePtr = NULL;
    266242
    267243    logoInfoAvailable = false;
    void ClassicCommDetector::SetVideoParams(float aspect) 
    735711void ClassicCommDetector::ProcessFrame(VideoFrame *frame,
    736712                                       long long frame_number)
    737713{
    738     int max = 0;
    739     int min = 255;
    740     int avg = 0;
    741     unsigned char pixel;
    742     int blankPixelsChecked = 0;
    743     long long totBrightness = 0;
    744     unsigned char *rowMax = new unsigned char[height];
    745     unsigned char *colMax = new unsigned char[width];
    746     memset(rowMax, 0, sizeof(*rowMax)*height);
    747     memset(colMax, 0, sizeof(*colMax)*width);
    748     int topDarkRow = commDetectBorder;
    749     int bottomDarkRow = height - commDetectBorder - 1;
    750     int leftDarkCol = commDetectBorder;
    751     int rightDarkCol = width - commDetectBorder - 1;
    752714    FrameInfoEntry fInfo;
    753715
    754     if (!frame || !(frame->buf) || frame_number == -1 ||
    755         frame->codec != FMT_YV12)
     716    if (!frame || !(frame->buf) || !width || !height ||
     717        frame_number == -1 || frame->codec != FMT_YV12)
    756718    {
    757719        LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Invalid video frame or codec, "
    758720                                  "unable to process frame.");
    759         delete[] rowMax;
    760         delete[] colMax;
    761         return;
    762     }
    763 
    764     if (!width || !height)
    765     {
    766         LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Width or Height is 0, "
    767                                   "unable to process frame.");
    768         delete[] rowMax;
    769         delete[] colMax;
    770721        return;
    771722    }
    772723
    void ClassicCommDetector::ProcessFrame(VideoFrame *frame, 
    803754
    804755    frameInfo[curFrameNumber] = fInfo;
    805756
    806     if (commDetectMethod & COMM_DETECT_BLANKS)
    807         frameIsBlank = false;
    808 
    809757    if (commDetectMethod & COMM_DETECT_SCENE)
    810758    {
    811         sceneChangeDetector->processFrame(framePtr);
     759        sceneChangeDetector->processFrame(curFrameNumber, framePtr);
    812760    }
    813 
    814     stationLogoPresent = false;
    815 
    816     for(int y = commDetectBorder; y < (height - commDetectBorder);
    817             y += vertSpacing)
     761   
     762    if (commDetectMethod & COMM_DETECT_BLANKS)
    818763    {
    819         for(int x = commDetectBorder; x < (width - commDetectBorder);
    820                 x += horizSpacing)
     764        unsigned char max = 0;
     765        unsigned char min = 255;
     766        unsigned char avg = 0;
     767        long long brightnessSum = 0;
     768       
     769        memset(colMax, 0, sizeof(*colMax)*width);
     770       
     771        unsigned int topLight = height, bottomLight = 0;
     772        for(unsigned int y = commDetectBorder; y < (height - commDetectBorder); ++y)
    821773        {
    822             pixel = framePtr[y * width + x];
    823 
    824             if (commDetectMethod & COMM_DETECT_BLANKS)
     774            for(unsigned int x = commDetectBorder; x < (width - commDetectBorder); x++)
    825775            {
    826                  bool checkPixel = false;
    827                  if (!commDetectBlankCanHaveLogo)
    828                      checkPixel = true;
    829 
    830                  if (!logoInfoAvailable)
    831                      checkPixel = true;
    832                  else if (!logoDetector->pixelInsideLogo(x,y))
    833                      checkPixel=true;
    834 
    835                  if (checkPixel)
    836                  {
    837                      blankPixelsChecked++;
    838                      totBrightness += pixel;
    839 
    840                      if (pixel < min)
    841                           min = pixel;
    842 
    843                      if (pixel > max)
    844                           max = pixel;
    845 
    846                      if (pixel > rowMax[y])
    847                          rowMax[y] = pixel;
    848 
    849                      if (pixel > colMax[x])
    850                          colMax[x] = pixel;
    851                  }
     776                unsigned char pixel = framePtr[y * width + x];
     777               
     778                brightnessSum += pixel;
     779                if (max < pixel)
     780                    max = pixel;
     781                if (min > pixel)
     782                    min = pixel;
     783               
     784                if (colMax[x] < pixel)
     785                    colMax[x] = pixel;
     786               
     787                if (pixel > commDetectBoxBrightness &&
     788                    (commDetectBlankCanHaveLogo ||
     789                     !logoInfoAvailable ||
     790                     !logoDetector->pixelInsideLogo(x,y)))
     791                {
     792                    if (topLight > y)
     793                        topLight = y;
     794                    bottomLight = y;
     795                }
    852796            }
    853797        }
    854     }
    855 
    856     if (commDetectMethod & COMM_DETECT_BLANKS)
    857     {
    858         for(int y = commDetectBorder; y < (height - commDetectBorder);
    859                 y += vertSpacing)
    860         {
    861             if (rowMax[y] > commDetectBoxBrightness)
    862                 break;
    863             else
    864                 topDarkRow = y;
    865         }
    866 
    867         for(int y = commDetectBorder; y < (height - commDetectBorder);
    868                 y += vertSpacing)
    869             if (rowMax[y] >= commDetectBoxBrightness)
    870                 bottomDarkRow = y;
    871 
    872         delete[] rowMax;
    873         rowMax = 0;
    874 
    875         for(int x = commDetectBorder; x < (width - commDetectBorder);
    876                 x += horizSpacing)
     798       
     799        unsigned int leftLight = width, rightLight = 0;
     800        for(unsigned int x = commDetectBorder; x < (width - commDetectBorder); x ++)
    877801        {
    878802            if (colMax[x] > commDetectBoxBrightness)
    879                 break;
    880             else
    881                 leftDarkCol = x;
     803            {
     804                if (leftLight > x)
     805                    leftLight = x;
     806               
     807                rightLight = x;
     808            }
    882809        }
    883 
    884         for(int x = commDetectBorder; x < (width - commDetectBorder);
    885                 x += horizSpacing)
    886             if (colMax[x] >= commDetectBoxBrightness)
    887                 rightDarkCol = x;
    888 
    889         delete[] colMax;
    890         colMax = 0;
    891 
    892         if ((topDarkRow > commDetectBorder) &&
    893             (topDarkRow < (height * .20)) &&
    894             (bottomDarkRow < (height - commDetectBorder)) &&
    895             (bottomDarkRow > (height * .80)))
     810       
     811        if (abs(leftLight - (width - rightLight)) < 5 &&
     812            leftLight <= width*0.2)
    896813        {
    897814            frameInfo[curFrameNumber].format = COMM_FORMAT_LETTERBOX;
    898815        }
    899         else if ((leftDarkCol > commDetectBorder) &&
    900                  (leftDarkCol < (width * .20)) &&
    901                  (rightDarkCol < (width - commDetectBorder)) &&
    902                  (rightDarkCol > (width * .80)))
     816        else if(abs(topLight - (height - bottomLight)) < 5 &&
     817                topLight <= height*0.2)
    903818        {
    904             frameInfo[curFrameNumber].format = COMM_FORMAT_PILLARBOX;
     819            frameInfo[curFrameNumber].format = COMM_FORMAT_LETTERBOX;
    905820        }
    906821        else
    907822        {
    908823            frameInfo[curFrameNumber].format = COMM_FORMAT_NORMAL;
    909824        }
    910 
    911         avg = totBrightness / blankPixelsChecked;
     825       
     826        avg = brightnessSum / (width * height);
    912827
    913828        frameInfo[curFrameNumber].minBrightness = min;
    914829        frameInfo[curFrameNumber].maxBrightness = max;
    void ClassicCommDetector::ProcessFrame(VideoFrame *frame, 
    916831
    917832        totalMinBrightness += min;
    918833        commDetectDimAverage = min + 10;
    919 
    920         // Is the frame really dark
    921         if (((max - min) <= commDetectBlankFrameMaxDiff) &&
    922             (max < commDetectDimBrightness))
    923             frameIsBlank = true;
    924 
    925         // Are we non-strict and the frame is blank
    926         if ((!aggressiveDetection) &&
    927             ((max - min) <= commDetectBlankFrameMaxDiff))
    928             frameIsBlank = true;
    929 
    930         // Are we non-strict and the frame is dark
    931         //                   OR the frame is dim and has a low avg brightness
    932         if ((!aggressiveDetection) &&
    933             ((max < commDetectDarkBrightness) ||
    934              ((max < commDetectDimBrightness) && (avg < commDetectDimAverage))))
    935             frameIsBlank = true;
     834       
     835        bool frameIsBlank;
     836        if (aggressiveDetection)
     837        {
     838            // Is the frame uniform AND dark
     839            frameIsBlank = (max - min) <= commDetectBlankFrameMaxDiff &&
     840                            max < commDetectDimBrightness;
     841        }
     842        else
     843        {
     844            // Is the frame uniform OR very dark OR dark and low average brightness
     845            frameIsBlank = (max - min) <= commDetectBlankFrameMaxDiff ||
     846                           max < commDetectDarkBrightness ||
     847                           (max < commDetectDimBrightness && avg < commDetectDimAverage);
     848        }
     849       
     850        if (frameIsBlank)
     851        {
     852            blankFrameMap[curFrameNumber] = MARK_BLANK_FRAME;
     853            flagMask |= COMM_FRAME_BLANK;
     854            blankFrameCount++;
     855        }
    936856    }
    937857
    938     if ((logoInfoAvailable) && (commDetectMethod & COMM_DETECT_LOGO))
     858    if (logoInfoAvailable && (commDetectMethod & COMM_DETECT_LOGO))
    939859    {
    940         stationLogoPresent =
    941             logoDetector->doesThisFrameContainTheFoundLogo(framePtr);
     860        if (logoDetector->doesThisFrameContainTheFoundLogo(framePtr))
     861            flagMask |= COMM_FRAME_LOGO_PRESENT;
    942862    }
    943863
    944864#if 0
    void ClassicCommDetector::ProcessFrame(VideoFrame *frame, 
    949869    }
    950870#endif
    951871
    952     if (frameIsBlank)
    953     {
    954         blankFrameMap[curFrameNumber] = MARK_BLANK_FRAME;
    955         flagMask |= COMM_FRAME_BLANK;
    956         blankFrameCount++;
    957     }
    958 
    959     if (stationLogoPresent)
    960         flagMask |= COMM_FRAME_LOGO_PRESENT;
    961 
    962872    //TODO: move this debugging code out of the perframe loop, and do it after
    963873    // we've processed all frames. this is because a scenechangedetector can
    964874    // now use a few frames to determine whether the frame a few frames ago was
    void ClassicCommDetector::ProcessFrame(VideoFrame *frame, 
    985895#endif
    986896
    987897    framesProcessed++;
    988     delete[] rowMax;
    989     delete[] colMax;
    990898}
    991899
    992900void ClassicCommDetector::ClearAllMaps(void)
    void ClassicCommDetector::UpdateFrameBlock(FrameBlock *fbp, 
    11401048                                           FrameInfoEntry finfo,
    11411049                                           int format, int aspect)
    11421050{
    1143     int value = 0;
    1144 
    1145     value = finfo.flagMask;
     1051    int value = finfo.flagMask;
    11461052
    11471053    if (value & COMM_FRAME_LOGO_PRESENT)
    11481054        fbp->logoCount++;
    void ClassicCommDetector::UpdateFrameBlock(FrameBlock *fbp, 
    11521058
    11531059    if (value & COMM_FRAME_SCENE_CHANGE)
    11541060        fbp->scCount++;
     1061   
     1062    if (value & COMM_FRAME_BLANK)
     1063        fbp->bfCount++;
    11551064
    11561065    if (finfo.format == format)
    11571066        fbp->formatMatch++;
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    11651074{
    11661075    LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildAllMethodsCommList()");
    11671076
    1168     FrameBlock *fblock;
    11691077    FrameBlock *fbp;
    1170     int value = 0;
    11711078    int curBlock = 0;
    11721079    int maxBlock = 0;
    11731080    int lastScore = 0;
    11741081    int thisScore = 0;
    1175     int nextScore = 0;
    11761082    uint64_t curFrame = 0;
    11771083    int64_t  breakStart = 0;
    11781084    uint64_t lastStart = 0;
    11791085    uint64_t lastEnd = 0;
    11801086    int64_t firstLogoFrame = -1;
    1181     bool nextFrameIsBlank = false;
    1182     bool lastFrameWasBlank = false;
    11831087    uint64_t formatFrames = 0;
    11841088    int format = COMM_FORMAT_NORMAL;
    11851089    uint64_t aspectFrames = 0;
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    11911095
    11921096    commBreakMap.clear();
    11931097
    1194     fblock = new FrameBlock[blankFrameCount + 2];
     1098    QVector<FrameBlock> fblock;
     1099    fblock.reserve(blankFrameCount + 2);
    11951100
    11961101    curBlock = 0;
    11971102    curFrame = 1;
    11981103
    1199     fbp = &fblock[curBlock];
     1104    fblock.resize(1);
     1105    fbp = &fblock[0];
    12001106    fbp->start = 0;
    12011107    fbp->bfCount = 0;
    12021108    fbp->logoCount = 0;
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    12451151            }
    12461152        }
    12471153    }
    1248 
     1154   
    12491155    while (curFrame <= framesProcessed)
    12501156    {
    1251         value = frameInfo[curFrame].flagMask;
    1252 
    1253         if (((curFrame + 1) <= framesProcessed) &&
    1254             (frameInfo[curFrame + 1].flagMask & COMM_FRAME_BLANK))
    1255             nextFrameIsBlank = true;
    1256         else
    1257             nextFrameIsBlank = false;
    1258 
    1259         if (value & COMM_FRAME_BLANK)
     1157        bool breakBlock = frameInfo[curFrame].flagMask & COMM_FRAME_BLANK;
     1158        /*if (!breakBlock &&
     1159            (frameInfo[curFrame].flagMask & COMM_FRAME_SCENE_CHANGE) &&
     1160            (frameInfo[curFrame].sceneChangePercent < 50))
    12601161        {
    1261             fbp->bfCount++;
    1262 
    1263             if (!nextFrameIsBlank || !lastFrameWasBlank)
     1162            double length = (curFrame - fbp->start) / fps;
     1163            if (abs(length -  5) < 0.10 ||
     1164                abs(length - 10) < 0.25 ||
     1165                abs(length - 15) < 0.50 ||
     1166                abs(length - 20) < 0.50 ||
     1167                abs(length - 30) < 0.50 ||
     1168                abs(length - 40) < 0.50 ||
     1169                abs(length - 45) < 0.75 ||
     1170                abs(length - 60) < 0.75 ||
     1171                abs(length - 90) < 1.00 ||
     1172                abs(length -120) < 1.00)
    12641173            {
    1265                 UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
    1266 
    1267                 fbp->end = curFrame;
    1268                 fbp->frames = fbp->end - fbp->start + 1;
    1269                 fbp->length = fbp->frames / fps;
    1270 
    1271                 if ((fbp->scCount) && (fbp->length > 1.05))
    1272                     fbp->scRate = fbp->scCount / fbp->length;
    1273 
    1274                 curBlock++;
    1275 
    1276                 fbp = &fblock[curBlock];
    1277                 fbp->bfCount = 1;
    1278                 fbp->logoCount = 0;
    1279                 fbp->ratingCount = 0;
    1280                 fbp->scCount = 0;
    1281                 fbp->scRate = 0.0;
    1282                 fbp->score = 0;
    1283                 fbp->formatMatch = 0;
    1284                 fbp->aspectMatch = 0;
    1285                 fbp->start = curFrame;
     1174                breakBlock = true;
     1175                // Make sure we weren't going to break because of blanks soon anyways
     1176                for (unsigned int f = 1; f < fps*2 && curFrame + f < framesProcessed; ++f)
     1177                {
     1178                    if (frameInfo[curFrame+f].flagMask & COMM_FRAME_BLANK)
     1179                    {
     1180                        breakBlock = false;
     1181                        break;
     1182                    }
     1183                }
    12861184            }
    1287 
    1288             lastFrameWasBlank = true;
     1185        }*/
     1186       
     1187        if (breakBlock)
     1188        {
     1189            unsigned int bfStart = curFrame, bfEnd = curFrame;
     1190            do
     1191            {
     1192                ++bfEnd;
     1193            }
     1194            while (bfEnd < framesProcessed && frameInfo[bfEnd].flagMask & COMM_FRAME_BLANK);
     1195           
     1196            unsigned int bfMiddle = curFrame + (bfEnd - bfStart)/2;
     1197           
     1198            do
     1199            {
     1200                UpdateFrameBlock(fbp, frameInfo[curFrame++], format, aspect);
     1201            }
     1202            while (curFrame < bfMiddle);
     1203           
     1204            fbp->end = curFrame;
     1205            fbp->frames = fbp->end - fbp->start + 1;
     1206            fbp->length = fbp->frames / fps;
     1207
     1208            if (fbp->length < 1.0)
     1209                fbp->scRate = fbp->scCount;
     1210            else
     1211                fbp->scRate = fbp->scCount / fbp->length; // changes per sec
     1212           
     1213            curBlock++;
     1214
     1215            fblock.resize(curBlock+1);
     1216            fbp = &fblock[curBlock];
     1217            fbp->bfCount = 0;
     1218            fbp->logoCount = 0;
     1219            fbp->ratingCount = 0;
     1220            fbp->scCount = 0;
     1221            fbp->scRate = 0.0;
     1222            fbp->score = 0;
     1223            fbp->formatMatch = 0;
     1224            fbp->aspectMatch = 0;
     1225           
     1226            fbp->start = curFrame;
     1227            for (; curFrame < bfEnd; ++curFrame)
     1228                UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
    12891229        }
    12901230        else
    12911231        {
    1292             lastFrameWasBlank = false;
     1232            UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
     1233            if ((frameInfo[curFrame].flagMask & COMM_FRAME_LOGO_PRESENT) && firstLogoFrame == -1)
     1234                firstLogoFrame = curFrame;
     1235            curFrame++;
    12931236        }
    1294 
    1295         UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
    1296 
    1297         if ((value & COMM_FRAME_LOGO_PRESENT) &&
    1298             (firstLogoFrame == -1))
    1299             firstLogoFrame = curFrame;
    1300 
    1301         curFrame++;
    13021237    }
    13031238
    13041239    fbp->end = curFrame;
    13051240    fbp->frames = fbp->end - fbp->start + 1;
    13061241    fbp->length = fbp->frames / fps;
    13071242
    1308     if ((fbp->scCount) && (fbp->length > 1.05))
    1309         fbp->scRate = fbp->scCount / fbp->length;
    1310 
     1243    if (fbp->length < 1.0)
     1244        fbp->scRate = fbp->scCount;
     1245    else
     1246        fbp->scRate = fbp->scCount / fbp->length; // changes per sec
     1247   
    13111248    maxBlock = curBlock;
    1312     curBlock = 0;
    1313     lastScore = 0;
    13141249
    13151250    LOG(VB_COMMFLAG, LOG_INFO, "Initial Block pass");
    13161251    LOG(VB_COMMFLAG, LOG_DEBUG,
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    13191254    LOG(VB_COMMFLAG, LOG_INFO,
    13201255        "----- ------ ------ ------ ------ ------- "
    13211256        "--- ------ ------ ------ ----- ------ ------ -----");
    1322     while (curBlock <= maxBlock)
     1257    for (curBlock = 0; curBlock <= maxBlock; ++curBlock)
    13231258    {
    13241259        fbp = &fblock[curBlock];
    13251260
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    13321267                    fbp->scCount, fbp->scRate, fbp->formatMatch,
    13331268                    fbp->aspectMatch, fbp->score);
    13341269        LOG(VB_COMMFLAG, LOG_DEBUG, msg);
    1335 
    1336         if (fbp->frames > fps)
     1270       
     1271        if ((int)fbp->length > commDetectMaxCommLength)
    13371272        {
    13381273            if (verboseDebugging)
    13391274                LOG(VB_COMMFLAG, LOG_DEBUG,
    1340                     QString("      FRAMES > %1").arg(fps));
    1341 
    1342             if (fbp->length > commDetectMaxCommLength)
    1343             {
    1344                 if (verboseDebugging)
    1345                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1346                         "      length > max comm length, +20");
    1347                 fbp->score += 20;
    1348             }
     1275                    "      length > max comm length, +10");
     1276            fbp->score += 10;
     1277        }
    13491278
    1350             if (fbp->length > commDetectMaxCommBreakLength)
    1351             {
    1352                 if (verboseDebugging)
    1353                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1354                         "      length > max comm break length, +20");
    1355                 fbp->score += 20;
    1356             }
     1279        if ((int)fbp->length > commDetectMaxCommBreakLength)
     1280        {
     1281            if (verboseDebugging)
     1282                LOG(VB_COMMFLAG, LOG_DEBUG,
     1283                    "      length > max comm break length, +20");
     1284            fbp->score += 20;
     1285        }
    13571286
    1358             if ((fbp->length > 4) &&
    1359                 (fbp->logoCount > (fbp->frames * 0.60)) &&
    1360                 (fbp->bfCount < (fbp->frames * 0.10)))
     1287        if ((fbp->logoCount > (fbp->frames * 0.20)) &&
     1288            (fbp->bfCount < (fbp->frames * 0.10)))
     1289        {
     1290            if (verboseDebugging)
     1291                LOG(VB_COMMFLAG, LOG_DEBUG,
     1292                    "      logoCount > frames * 0.20 && "
     1293                    "bfCount < frames * .10, +10");
     1294            fbp->score += 10;
     1295           
     1296            if (fbp->logoCount > (fbp->frames * 0.50))
    13611297            {
    13621298                if (verboseDebugging)
    13631299                    LOG(VB_COMMFLAG, LOG_DEBUG,
    1364                         "      length > 4 && logoCount > frames * 0.60 && "
    1365                         "bfCount < frames * .10");
    1366                 if (fbp->length > commDetectMaxCommBreakLength)
    1367                 {
    1368                     if (verboseDebugging)
    1369                         LOG(VB_COMMFLAG, LOG_DEBUG,
    1370                             "      length > max comm break length, +20");
    1371                     fbp->score += 20;
    1372                 }
    1373                 else
     1300                        "      logoCount > frames * 0.50, +10");
     1301                fbp->score += 10;
     1302                if (fbp->logoCount > (fbp->frames * 0.75))
    13741303                {
    13751304                    if (verboseDebugging)
    13761305                        LOG(VB_COMMFLAG, LOG_DEBUG,
    1377                             "      length <= max comm break length, +10");
     1306                            "      logoCount > frames * 0.75, +10");
    13781307                    fbp->score += 10;
    13791308                }
    13801309            }
     1310        }
     1311        else if ((logoInfoAvailable) &&
     1312                (fbp->logoCount < (fbp->frames * 0.10)))
     1313        {
     1314            if (verboseDebugging)
     1315                LOG(VB_COMMFLAG, LOG_DEBUG,
     1316                    "      logoInfoAvailable && logoCount < frames * .10, "
     1317                    "-10");
     1318            fbp->score -= 10;
     1319        }
    13811320
    1382             if ((logoInfoAvailable) &&
    1383                 (fbp->logoCount < (fbp->frames * 0.50)))
    1384             {
    1385                 if (verboseDebugging)
    1386                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1387                         "      logoInfoAvailable && logoCount < frames * .50, "
    1388                         "-10");
    1389                 fbp->score -= 10;
    1390             }
     1321        if (fbp->ratingCount > 5 * fps)
     1322        {
     1323            if (verboseDebugging)
     1324                LOG(VB_COMMFLAG, LOG_DEBUG,
     1325                    "      rating present > 5 seconds, +20");
     1326            fbp->score += 20;
     1327        }
    13911328
    1392             if (fbp->ratingCount > (fbp->frames * 0.05))
    1393             {
    1394                 if (verboseDebugging)
    1395                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1396                         "      rating symbol present > 5% of time, +20");
    1397                 fbp->score += 20;
    1398             }
     1329        if ((fbp->scRate > 0.5) &&
     1330            (fbp->logoCount < (fbp->frames * .25)))
     1331        {
     1332            if (verboseDebugging)
     1333                LOG(VB_COMMFLAG, LOG_DEBUG, "      scRate > 0.5, -10");
     1334            fbp->score -= 10;
    13991335
    1400             if ((fbp->scRate > 1.0) &&
    1401                 (fbp->logoCount < (fbp->frames * .90)))
     1336            if (fbp->scRate > 1.0)
    14021337            {
    14031338                if (verboseDebugging)
    14041339                    LOG(VB_COMMFLAG, LOG_DEBUG, "      scRate > 1.0, -10");
    14051340                fbp->score -= 10;
    1406 
    1407                 if (fbp->scRate > 2.0)
    1408                 {
    1409                     if (verboseDebugging)
    1410                         LOG(VB_COMMFLAG, LOG_DEBUG, "      scRate > 2.0, -10");
    1411                     fbp->score -= 10;
    1412                 }
    14131341            }
     1342        }
     1343        else if (fbp->scRate < 0.20)
     1344        {
     1345            if (verboseDebugging)
     1346                LOG(VB_COMMFLAG, LOG_DEBUG, "      scRate < 0.20, +10");
     1347            fbp->score += 10;
     1348        }
    14141349
    1415             if ((!decoderFoundAspectChanges) &&
    1416                 (fbp->formatMatch < (fbp->frames * .10)))
    1417             {
    1418                 if (verboseDebugging)
    1419                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1420                         "      < 10% of frames match show letter/pillar-box "
    1421                         "format, -20");
    1422                 fbp->score -= 20;
    1423             }
     1350        if ((!decoderFoundAspectChanges) &&
     1351            (fbp->formatMatch < (fbp->frames * .10)))
     1352        {
     1353            if (verboseDebugging)
     1354                LOG(VB_COMMFLAG, LOG_DEBUG,
     1355                    "      < 10% of frames match show letter/pillar-box "
     1356                    "format, -20");
     1357            fbp->score -= 20;
     1358        }
    14241359
    1425             if ((abs((int)(fbp->frames - (15 * fps))) < 5 ) ||
    1426                 (abs((int)(fbp->frames - (30 * fps))) < 6 ) ||
    1427                 (abs((int)(fbp->frames - (60 * fps))) < 8 ))
    1428             {
    1429                 if (verboseDebugging)
    1430                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1431                         "      block appears to be standard comm length, -10");
    1432                 fbp->score -= 10;
    1433             }
     1360        if (abs(fbp->length -  5) < 0.10 ||
     1361            abs(fbp->length - 10) < 0.25 ||
     1362            abs(fbp->length - 15) < 0.50 ||
     1363            abs(fbp->length - 20) < 0.50 ||
     1364            abs(fbp->length - 30) < 0.50 ||
     1365            abs(fbp->length - 40) < 0.50 ||
     1366            abs(fbp->length - 45) < 0.75 ||
     1367            abs(fbp->length - 60) < 0.75 ||
     1368            abs(fbp->length - 90) < 1.00 ||
     1369            abs(fbp->length -120) < 1.00)
     1370        {
     1371            if (verboseDebugging)
     1372                LOG(VB_COMMFLAG, LOG_DEBUG,
     1373                    "      block appears to be standard comm length, -10");
     1374            fbp->score -= 10;
    14341375        }
    1435         else
     1376       
     1377        if (fbp->length < 30 && fbp->bfCount > (fbp->frames * 0.90))
    14361378        {
    14371379            if (verboseDebugging)
    14381380                LOG(VB_COMMFLAG, LOG_DEBUG,
    1439                     QString("      FRAMES <= %1").arg(fps));
    1440 
    1441             if ((logoInfoAvailable) &&
    1442                 (fbp->start >= firstLogoFrame) &&
    1443                 (fbp->logoCount == 0))
    1444             {
    1445                 if (verboseDebugging)
    1446                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1447                         "      logoInfoAvailable && logoCount == 0, -10");
    1448                 fbp->score -= 10;
    1449             }
    1450 
    1451             if ((!decoderFoundAspectChanges) &&
    1452                 (fbp->formatMatch < (fbp->frames * .10)))
    1453             {
    1454                 if (verboseDebugging)
    1455                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1456                         "      < 10% of frames match show letter/pillar-box "
    1457                         "format, -10");
    1458                 fbp->score -= 10;
    1459             }
    1460 
    1461             if (fbp->ratingCount > (fbp->frames * 0.25))
    1462             {
    1463                 if (verboseDebugging)
    1464                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1465                         "      rating symbol present > 25% of time, +10");
    1466                 fbp->score += 10;
    1467             }
     1381                    "      blength < 30 && "
     1382                    "bfCount > frames * .9, -10");
     1383            fbp->score -= 10;
    14681384        }
    1469 
     1385       
    14701386        if ((decoderFoundAspectChanges) &&
    14711387            (fbp->aspectMatch < (fbp->frames * .10)))
    14721388        {
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    14751391                    "      < 10% of frames match show aspect, -20");
    14761392            fbp->score -= 20;
    14771393        }
    1478 
    1479         msg.sprintf("  NOW %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
    1480                     "%5.2f %6d %6d %5d",
    1481                     (int)(fbp->start / fps) / 60,
    1482                     (int)((fbp->start / fps )) % 60,
    1483                     fbp->start, fbp->end, fbp->frames, fbp->length,
    1484                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
    1485                     fbp->scCount, fbp->scRate, fbp->formatMatch,
    1486                     fbp->aspectMatch, fbp->score);
    1487         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
    1488 
    1489         lastScore = fbp->score;
    1490         curBlock++;
    1491     }
    1492 
    1493     curBlock = 0;
    1494     lastScore = 0;
    1495 
    1496     LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
    1497     LOG(VB_COMMFLAG, LOG_INFO, "Second Block pass");
    1498     LOG(VB_COMMFLAG, LOG_DEBUG,
    1499         "Block StTime StFrm  EndFrm Frames Secs    "
    1500         "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
    1501     LOG(VB_COMMFLAG, LOG_DEBUG,
    1502         "----- ------ ------ ------ ------ ------- "
    1503         "--- ------ ------ ------ ----- ------ ------ -----");
    1504     while (curBlock <= maxBlock)
    1505     {
    1506         fbp = &fblock[curBlock];
    1507 
    1508         msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
    1509                     "%5.2f %6d %6d %5d",
    1510                     curBlock, (int)(fbp->start / fps) / 60,
    1511                     (int)((fbp->start / fps )) % 60,
    1512                     fbp->start, fbp->end, fbp->frames, fbp->length,
    1513                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
    1514                     fbp->scCount, fbp->scRate, fbp->formatMatch,
    1515                     fbp->aspectMatch, fbp->score);
    1516         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
    1517 
    1518         if ((curBlock > 0) && (curBlock < maxBlock))
    1519         {
    1520             nextScore = fblock[curBlock + 1].score;
    1521 
    1522             if ((lastScore < 0) && (nextScore < 0) && (fbp->length < 35))
    1523             {
    1524                 if (verboseDebugging)
    1525                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1526                         "      lastScore < 0 && nextScore < 0 "
    1527                         "&& length < 35, setting -10");
    1528                 fbp->score -= 10;
    1529             }
    1530 
    1531             if ((fbp->bfCount > (fbp->frames * 0.95)) &&
    1532                 (fbp->frames < (2*fps)) &&
    1533                 (lastScore < 0 && nextScore < 0))
    1534             {
    1535                 if (verboseDebugging)
    1536                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1537                         "      blanks > frames * 0.95 && frames < 2*fps && "
    1538                         "lastScore < 0 && nextScore < 0, setting -10");
    1539                 fbp->score -= 10;
    1540             }
    1541 
    1542             if ((fbp->frames < (120*fps)) &&
    1543                 (lastScore < 0) &&
    1544                 (fbp->score > 0) &&
    1545                 (fbp->score < 20) &&
    1546                 (nextScore < 0))
    1547             {
    1548                 if (verboseDebugging)
    1549                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1550                         "      frames < 120 * fps && (-20 < lastScore < 0) && "
    1551                         "thisScore > 0 && nextScore < 0, setting score = -10");
    1552                 fbp->score = -10;
    1553             }
    1554 
    1555             if ((fbp->frames < (30*fps)) &&
    1556                 (lastScore > 0) &&
    1557                 (fbp->score < 0) &&
    1558                 (fbp->score > -20) &&
    1559                 (nextScore > 0))
    1560             {
    1561                 if (verboseDebugging)
    1562                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1563                         "      frames < 30 * fps && (0 < lastScore < 20) && "
    1564                         "thisScore < 0 && nextScore > 0, setting score = 10");
    1565                 fbp->score = 10;
    1566             }
    1567         }
    1568 
    1569         if ((fbp->score == 0) && (lastScore > 30))
     1394       
     1395        if (fbp->score == 0 && fbp->length < 2)
    15701396        {
    1571             int offset = 1;
    1572             while(((curBlock + offset) <= maxBlock) &&
    1573                     (fblock[curBlock + offset].frames < (2 * fps)) &&
    1574                     (fblock[curBlock + offset].score == 0))
    1575                 offset++;
    1576 
    1577             if ((curBlock + offset) <= maxBlock)
    1578             {
    1579                 offset--;
    1580                 if (fblock[curBlock + offset + 1].score > 0)
    1581                 {
    1582                     for (; offset >= 0; offset--)
    1583                     {
    1584                         fblock[curBlock + offset].score += 10;
    1585                         if (verboseDebugging)
    1586                             LOG(VB_COMMFLAG, LOG_DEBUG,
    1587                                 QString("      Setting block %1 score +10")
    1588                                     .arg(curBlock+offset));
    1589                     }
    1590                 }
    1591                 else if (fblock[curBlock + offset + 1].score < 0)
    1592                 {
    1593                     for (; offset >= 0; offset--)
    1594                     {
    1595                         fblock[curBlock + offset].score -= 10;
    1596                         if (verboseDebugging)
    1597                             LOG(VB_COMMFLAG, LOG_DEBUG,
    1598                                 QString("      Setting block %1 score -10")
    1599                                     .arg(curBlock+offset));
    1600                     }
    1601                 }
    1602             }
     1397            if (verboseDebugging)
     1398                LOG(VB_COMMFLAG, LOG_DEBUG,
     1399                    "      length < 2 && score == 0, -10");
     1400            fbp->score = -10;
    16031401        }
    1604 
     1402       
    16051403        msg.sprintf("  NOW %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
    16061404                    "%5.2f %6d %6d %5d",
    16071405                    (int)(fbp->start / fps) / 60,
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    16111409                    fbp->scCount, fbp->scRate, fbp->formatMatch,
    16121410                    fbp->aspectMatch, fbp->score);
    16131411        LOG(VB_COMMFLAG, LOG_DEBUG, msg);
    1614 
     1412       
    16151413        lastScore = fbp->score;
    1616         curBlock++;
    16171414    }
    1618 
     1415   
    16191416    LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
    16201417    LOG(VB_COMMFLAG, LOG_INFO, "FINAL Block stats");
    16211418    LOG(VB_COMMFLAG, LOG_DEBUG,
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    16241421    LOG(VB_COMMFLAG, LOG_DEBUG,
    16251422        "----- ------ ------ ------ ------ ------- "
    16261423        "--- ------ ------ ------ ----- ------ ------ -----");
    1627     curBlock = 0;
    1628     lastScore = 0;
     1424    lastScore = lastStart = lastEnd = 0;
    16291425    breakStart = -1;
    1630     while (curBlock <= maxBlock)
     1426    for (curBlock = 0; curBlock <= maxBlock; ++curBlock)
    16311427    {
    16321428        fbp = &fblock[curBlock];
    16331429        thisScore = fbp->score;
    1634 
    1635         if ((breakStart >= 0) &&
    1636             ((fbp->end - breakStart) > (commDetectMaxCommBreakLength * fps)))
     1430        if (thisScore == 0)
     1431            thisScore = lastScore;
     1432        lastScore = thisScore;
     1433       
     1434        if (thisScore < 0 && breakStart == -1)
    16371435        {
    1638             if (((fbp->start - breakStart) >
    1639                 (commDetectMinCommBreakLength * fps)) ||
    1640                 (breakStart == 0))
     1436            if (curBlock > 0 &&
     1437               (fbp->start - lastEnd) < (commDetectMinShowLength * fps))
    16411438            {
     1439                commBreakMap.remove(lastStart);
     1440                commBreakMap.remove(lastEnd);
     1441                breakStart = lastStart;
     1442
    16421443                if (verboseDebugging)
     1444                {
    16431445                    LOG(VB_COMMFLAG, LOG_DEBUG,
    1644                         QString("Closing commercial block at start of "
    1645                                 "frame block %1 with length %2, frame "
    1646                                 "block length of %3 frames would put comm "
    1647                                 "block length over max of %4 seconds.")
    1648                             .arg(curBlock).arg(fbp->start - breakStart)
    1649                             .arg(fbp->frames)
    1650                             .arg(commDetectMaxCommBreakLength));
    1651 
    1652                 commBreakMap[breakStart] = MARK_COMM_START;
    1653                 commBreakMap[fbp->start] = MARK_COMM_END;
    1654                 lastStart = breakStart;
    1655                 lastEnd = fbp->start;
    1656                 breakStart = -1;
     1446                        QString("ReOpening commercial block at "
     1447                                "frame %1 because show less than "
     1448                                "%2 seconds")
     1449                            .arg(breakStart)
     1450                            .arg(commDetectMinShowLength));
     1451                }
    16571452            }
    16581453            else
    16591454            {
     1455                breakStart = fbp->start;
     1456
    16601457                if (verboseDebugging)
    16611458                    LOG(VB_COMMFLAG, LOG_DEBUG,
    1662                         QString("Ignoring what appears to be commercial"
    1663                                 " block at frame %1 with length %2, "
    1664                                 "length of %3 frames would put comm "
    1665                                 "block length under min of %4 seconds.")
    1666                             .arg(breakStart)
    1667                             .arg(fbp->start - breakStart)
    1668                             .arg(fbp->frames)
    1669                             .arg(commDetectMinCommBreakLength));
    1670                 breakStart = -1;
     1459                        QString("Starting new commercial block at "
     1460                                "frame %1 from start of frame block %2")
     1461                            .arg(fbp->start).arg(curBlock));
    16711462            }
     1463            lastStart = breakStart;
    16721464        }
    1673         if (thisScore == 0)
     1465       
     1466        if(breakStart >= 0 && (
     1467            // Break should stop (by score)
     1468            thisScore >= 0 ||
     1469            // Break must stop at end of recording
     1470            curBlock == maxBlock ||
     1471            // Break will be too long
     1472            (fbp->end - breakStart) >= commDetectMaxCommBreakLength * fps
     1473          ))
    16741474        {
    1675             thisScore = lastScore;
    1676         }
    1677         else if (thisScore < 0)
    1678         {
    1679             if ((lastScore > 0) || (curBlock == 0))
     1475            unsigned int endOfBreak = fbp->start;
     1476            if (thisScore < 0 &&
     1477                curBlock == maxBlock &&
     1478                (fbp->end - breakStart) < commDetectMaxCommBreakLength * fps)
    16801479            {
    1681                 if ((fbp->start - lastEnd) < (commDetectMinShowLength * fps))
    1682                 {
    1683                     commBreakMap.remove(lastStart);
    1684                     commBreakMap.remove(lastEnd);
    1685                     breakStart = lastStart;
    1686 
    1687                     if (verboseDebugging)
    1688                     {
    1689                         if (breakStart)
    1690                             LOG(VB_COMMFLAG, LOG_DEBUG,
    1691                                 QString("ReOpening commercial block at "
    1692                                         "frame %1 because show less than "
    1693                                         "%2 seconds")
    1694                                     .arg(breakStart)
    1695                                     .arg(commDetectMinShowLength));
    1696                         else
    1697                             LOG(VB_COMMFLAG, LOG_DEBUG,
    1698                                 "Opening initial commercial block "
    1699                                 "at start of recording, block 0.");
    1700                     }
    1701                 }
    1702                 else
    1703                 {
    1704                     breakStart = fbp->start;
    1705 
    1706                     if (verboseDebugging)
    1707                         LOG(VB_COMMFLAG, LOG_DEBUG,
    1708                             QString("Starting new commercial block at "
    1709                                     "frame %1 from start of frame block %2")
    1710                                 .arg(fbp->start).arg(curBlock));
    1711                 }
     1480                // Create what is essentially an open-ended final skip region
     1481                // by setting the end point 10 seconds past the end of the
     1482                // recording.
     1483                endOfBreak = fbp->end + (10 * fps);
     1484               
     1485                if (verboseDebugging)
     1486                    LOG(VB_COMMFLAG, LOG_DEBUG,
     1487                        "    At end of recording.");
    17121488            }
    1713             else if (curBlock == maxBlock)
     1489           
     1490            if ((endOfBreak - breakStart) >= (commDetectMinCommBreakLength * fps))
    17141491            {
    1715                 if ((fbp->end - breakStart) >
    1716                     (commDetectMinCommBreakLength * fps))
     1492                if (verboseDebugging)
    17171493                {
    1718                     if (fbp->end <=
    1719                         ((int64_t)framesProcessed - (int64_t)(2 * fps) - 2))
     1494                    LOG(VB_COMMFLAG, LOG_DEBUG,
     1495                        QString("Closing commercial block at "
     1496                                "frame %1 from frame block %2, length %3")
     1497                            .arg(endOfBreak).arg(curBlock)
     1498                            .arg(endOfBreak - breakStart));
     1499                   
     1500                    if (thisScore < 0 &&
     1501                        (fbp->end - breakStart) >= commDetectMaxCommBreakLength * fps)
    17201502                    {
    1721                         if (verboseDebugging)
    1722                             LOG(VB_COMMFLAG, LOG_DEBUG,
    1723                                 QString("Closing final commercial block at "
    1724                                         "frame %1").arg(fbp->end));
    1725 
    1726                         commBreakMap[breakStart] = MARK_COMM_START;
    1727                         commBreakMap[fbp->end] = MARK_COMM_END;
    1728                         lastStart = breakStart;
    1729                         lastEnd = fbp->end;
    1730                         breakStart = -1;
    1731                     }
    1732                 }
    1733                 else
    1734                 {
    1735                     if (verboseDebugging)
    17361503                        LOG(VB_COMMFLAG, LOG_DEBUG,
    1737                             QString("Ignoring what appears to be commercial"
    1738                                     " block at frame %1 with length %2, "
    1739                                     "length of %3 frames would put comm "
    1740                                     "block length under min of %4 seconds.")
    1741                                 .arg(breakStart)
    1742                                 .arg(fbp->start - breakStart)
     1504                            QString("    Frame block length of %1 frames would put comm "
     1505                                    "block length over max of %2 seconds.")
    17431506                                .arg(fbp->frames)
    1744                                 .arg(commDetectMinCommBreakLength));
    1745                     breakStart = -1;
     1507                                .arg(commDetectMaxCommBreakLength));
     1508                    }
    17461509                }
    1747             }
    1748         }
    1749         else if ((thisScore > 0) &&
    1750                  (lastScore < 0) &&
    1751                  (breakStart != -1))
    1752         {
    1753             if (((fbp->start - breakStart) >
    1754                 (commDetectMinCommBreakLength * fps)) ||
    1755                 (breakStart == 0))
    1756             {
     1510
    17571511                commBreakMap[breakStart] = MARK_COMM_START;
    1758                 commBreakMap[fbp->start] = MARK_COMM_END;
     1512                commBreakMap[endOfBreak] = MARK_COMM_END;
    17591513                lastStart = breakStart;
    1760                 lastEnd = fbp->start;
    1761 
    1762                 if (verboseDebugging)
    1763                     LOG(VB_COMMFLAG, LOG_DEBUG,
    1764                         QString("Closing commercial block at frame %1")
    1765                             .arg(fbp->start));
     1514                lastEnd = endOfBreak;
    17661515            }
    17671516            else
    17681517            {
    17691518                if (verboseDebugging)
    17701519                    LOG(VB_COMMFLAG, LOG_DEBUG,
    1771                         QString("Ignoring what appears to be commercial "
    1772                                 "block at frame %1 with length %2, "
    1773                                 "length of %3 frames would put comm block "
    1774                                 "length under min of %4 seconds.")
     1520                        QString("Ignoring what appears to be commercial"
     1521                                " block at frame %1 with length %2, "
     1522                                "block length would be under min of %3 seconds.")
    17751523                            .arg(breakStart)
    1776                             .arg(fbp->start - breakStart)
    1777                             .arg(fbp->frames)
     1524                            .arg(endOfBreak - breakStart)
    17781525                            .arg(commDetectMinCommBreakLength));
    17791526            }
    17801527            breakStart = -1;
    17811528        }
    1782 
     1529       
    17831530        msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
    17841531                    "%5.2f %6d %6d %5d",
    17851532                    curBlock, (int)(fbp->start / fps) / 60,
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    17891536                    fbp->scCount, fbp->scRate, fbp->formatMatch,
    17901537                    fbp->aspectMatch, thisScore);
    17911538        LOG(VB_COMMFLAG, LOG_DEBUG, msg);
    1792 
    1793         lastScore = thisScore;
    1794         curBlock++;
    1795     }
    1796 
    1797     if ((breakStart != -1) &&
    1798         (breakStart <= ((int64_t)framesProcessed - (int64_t)(2 * fps) - 2)))
    1799     {
    1800         if (verboseDebugging)
    1801             LOG(VB_COMMFLAG, LOG_DEBUG,
    1802                 QString("Closing final commercial block started at "
    1803                         "block %1 and going to end of program. length "
    1804                         "is %2 frames")
    1805                     .arg(curBlock)
    1806                     .arg((framesProcessed - breakStart - 1)));
    1807 
    1808         commBreakMap[breakStart] = MARK_COMM_START;
    1809         // Create what is essentially an open-ended final skip region
    1810         // by setting the end point 10 seconds past the end of the
    1811         // recording.
    1812         commBreakMap[framesProcessed + (10 * fps)] = MARK_COMM_END;
    18131539    }
    18141540
    18151541    // include/exclude blanks from comm breaks
    void ClassicCommDetector::BuildAllMethodsCommList(void) 
    18211547            "Adjusting start/end marks according to blanks.");
    18221548    for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
    18231549    {
    1824         if (*it == MARK_COMM_START)
    1825         {
    1826             uint64_t lastStartLower = it.key();
    1827             uint64_t lastStartUpper = it.key();
    1828             while ((lastStartLower > 0) &&
    1829                    (frameInfo[lastStartLower - 1].flagMask & COMM_FRAME_BLANK))
    1830                 lastStartLower--;
    1831             while ((lastStartUpper < (framesProcessed - (2 * fps))) &&
    1832                    (frameInfo[lastStartUpper + 1].flagMask & COMM_FRAME_BLANK))
    1833                 lastStartUpper++;
    1834             uint64_t adj = (lastStartUpper - lastStartLower) / 2;
    1835             if (adj > MAX_BLANK_FRAMES)
    1836                 adj = MAX_BLANK_FRAMES;
    1837             lastStart = lastStartLower + adj;
    1838 
    1839             if (verboseDebugging)
    1840                 LOG(VB_COMMFLAG, LOG_DEBUG, QString("Start Mark: %1 -> %2")
    1841                         .arg(it.key()).arg(lastStart));
    1842 
    1843             commBreakMap[lastStart] = MARK_COMM_START;
    1844         }
    1845         else
    1846         {
    1847             uint64_t lastEndLower = it.key();
    1848             uint64_t lastEndUpper = it.key();
    1849             while ((lastEndUpper < (framesProcessed - (2 * fps))) &&
    1850                    (frameInfo[lastEndUpper + 1].flagMask & COMM_FRAME_BLANK))
    1851                 lastEndUpper++;
    1852             while ((lastEndLower > 0) &&
    1853                    (frameInfo[lastEndLower - 1].flagMask & COMM_FRAME_BLANK))
    1854                 lastEndLower--;
    1855             uint64_t adj = (lastEndUpper - lastEndLower) / 2;
    1856             if (adj > MAX_BLANK_FRAMES)
    1857                 adj = MAX_BLANK_FRAMES;
    1858             lastEnd = lastEndUpper - adj;
    1859 
    1860             if (verboseDebugging)
    1861                 LOG(VB_COMMFLAG, LOG_DEBUG, QString("End Mark  : %1 -> %2")
    1862                         .arg(it.key()).arg(lastEnd));
    1863 
    1864             commBreakMap[lastEnd] = MARK_COMM_END;
    1865         }
     1550        uint64_t blankStart, blankEnd;
     1551        blankStart = blankEnd = it.key();
     1552       
     1553        while (blankStart > 0 && frameInfo[blankStart].flagMask & COMM_FRAME_BLANK)
     1554            --blankStart;
     1555        while (blankEnd < framesProcessed && frameInfo[blankEnd].flagMask & COMM_FRAME_BLANK)
     1556            ++blankEnd;
     1557       
     1558        uint64_t split = blankStart + (blankEnd - blankStart) / 2;
     1559       
     1560        commBreakMap[split] = *it;
     1561       
     1562        if (verboseDebugging)
     1563            LOG(VB_COMMFLAG, LOG_DEBUG, QString("Adjusted Mark %1: %2 -> %3")
     1564                    .arg(*it).arg(it.key()).arg(split));
    18661565    }
    1867 
    1868     delete [] fblock;
    18691566}
    18701567
    18711568
  • mythtv/programs/mythcommflag/ClassicCommDetector.h

    diff --git a/mythtv/programs/mythcommflag/ClassicCommDetector.h b/mythtv/programs/mythcommflag/ClassicCommDetector.h
    index f9e5c4c..f397fec 100644
    a b class ClassicCommDetector : public CommDetectorBase 
    142142        bool blankFramesOnly;
    143143        int blankFrameCount;
    144144        int currentAspect;
    145 
     145        unsigned char *colMax;
    146146
    147147        int totalMinBrightness;
    148148
  • mythtv/programs/mythcommflag/ClassicLogoDetector.cpp

    diff --git a/mythtv/programs/mythcommflag/ClassicLogoDetector.cpp b/mythtv/programs/mythcommflag/ClassicLogoDetector.cpp
    index f961af0..6db9e12 100644
    a b  
    66
    77// MythTV headers
    88#include "mythcorecontext.h"
    9 #include "mythplayer.h"
     9#include "mythcommflagplayer.h"
    1010
    1111// Commercial Flagging headers
    1212#include "ClassicLogoDetector.h"
    1313#include "ClassicCommDetector.h"
    14 
    15 typedef struct edgemaskentry
    16 {
    17     int isedge;
    18     int horiz;
    19     int vert;
    20     int rdiag;
    21     int ldiag;
    22 }
    23 EdgeMaskEntry;
    24 
     14#include <ffmpeg-mmx.h>
     15#include <lzoconf.h>
    2516
    2617ClassicLogoDetector::ClassicLogoDetector(ClassicCommDetector* commdetector,
    2718                                         unsigned int w, unsigned int h,
    ClassicLogoDetector::ClassicLogoDetector(ClassicCommDetector* commdetector, 
    2920                                         unsigned int xspacing_in,
    3021                                         unsigned int yspacing_in)
    3122    : LogoDetectorBase(w,h),
    32       commDetector(commdetector),                       frameNumber(0),
    33       previousFrameWasSceneChange(false),
    34       xspacing(xspacing_in),                            yspacing(yspacing_in),
    35       commDetectBorder(commdetectborder_in),            edgeMask(new EdgeMaskEntry[width * height]),
    36       logoMaxValues(new unsigned char[width * height]), logoMinValues(new unsigned char[width * height]),
    37       logoFrame(new unsigned char[width * height]),     logoMask(new unsigned char[width * height]),
    38       logoCheckMask(new unsigned char[width * height]), tmpBuf(new unsigned char[width * height]),
    39       logoEdgeDiff(0),                                  logoFrameCount(0),
    40       logoMinX(0),                                      logoMaxX(0),
    41       logoMinY(0),                                      logoMaxY(0),
    42       logoInfoAvailable(false)
     23      commDetector(commdetector), commDetectBorder(commdetectborder_in),
     24      logoInfoAvailable(false),   logoEdgeDiff(0),
     25      logoMinX(0),                logoWidth(0),
     26      logoMinY(0),                logoHeight(0)
    4327{
    4428    commDetectLogoSamplesNeeded =
    4529        gCoreContext->GetNumSetting("CommDetectLogoSamplesNeeded", 240);
    unsigned int ClassicLogoDetector::getRequiredAvailableBufferForSearch() 
    6347void ClassicLogoDetector::deleteLater(void)
    6448{
    6549    commDetector = 0;
    66     if (edgeMask)
    67         delete [] edgeMask;
    68     if (logoFrame)
    69         delete [] logoFrame;
    70     if (logoMask)
    71         delete [] logoMask;
    72     if (logoCheckMask)
    73         delete [] logoCheckMask;
    74     if (logoMaxValues)
    75         delete [] logoMaxValues;
    76     if (logoMinValues)
    77         delete [] logoMinValues;
    78     if (tmpBuf)
    79         delete [] tmpBuf;
    80 
     50   
    8151    LogoDetectorBase::deleteLater();
    8252}
    8353
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    8858    long long seekFrame;
    8959    int loops;
    9060    int maxLoops = commDetectLogoSamplesNeeded;
    91     EdgeMaskEntry *edgeCounts;
    92     unsigned int pos, i, x, y, dx, dy;
    93     int edgeDiffs[] = {5, 7, 10, 15, 20, 30, 40, 50, 60, 0 };
    94 
    95 
     61    const int edgeDiffs[] = {55, 25, 13, 6, 0};
     62   
    9663    LOG(VB_COMMFLAG, LOG_INFO, "Searching for Station Logo");
    9764
    9865    logoInfoAvailable = false;
    9966
    100     edgeCounts = new EdgeMaskEntry[width * height];
     67    int *edgeCounts = new int[width * height];
    10168
    102     for (i = 0; edgeDiffs[i] != 0 && !logoInfoAvailable; i++)
     69    for (int i = 0; edgeDiffs[i] != 0 && !logoInfoAvailable; i++)
    10370    {
    10471        int pixelsInMask = 0;
    10572
    10673        LOG(VB_COMMFLAG, LOG_INFO, QString("Trying with edgeDiff == %1")
    10774                .arg(edgeDiffs[i]));
    10875
    109         memset(edgeCounts, 0, sizeof(EdgeMaskEntry) * width * height);
    110         memset(edgeMask, 0, sizeof(EdgeMaskEntry) * width * height);
     76        memset(edgeCounts, 0, sizeof(int) * width * height);
     77        edgeMask.clear();
    11178
    11279        player->DiscardVideoFrame(player->GetRawVideoFrame(0));
    11380
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    11582        seekFrame = commDetector->preRoll + seekIncrement;
    11683        while(loops < maxLoops && !player->GetEof())
    11784        {
    118             VideoFrame* vf = player->GetRawVideoFrame(seekFrame);
    119 
    12085            if ((loops % 50) == 0)
    12186                commDetector->logoDetectorBreathe();
    12287
     88            if (!commDetector->fullSpeed)
     89                usleep(10000);
     90           
     91            VideoFrame* vf = player->GetRawVideoFrame(seekFrame);
     92            DetectEdges(vf, edgeCounts, edgeDiffs[i]);
     93            player->DiscardVideoFrame(vf);
     94           
    12395            if (commDetector->m_bStop)
    12496            {
    125                 player->DiscardVideoFrame(vf);
    12697                delete[] edgeCounts;
    12798                return false;
    12899            }
    129 
    130             if (!commDetector->fullSpeed)
    131                 usleep(10000);
    132 
    133             DetectEdges(vf, edgeCounts, edgeDiffs[i]);
    134 
     100           
    135101            seekFrame += seekIncrement;
    136102            loops++;
    137 
    138             player->DiscardVideoFrame(vf);
    139         }
    140 
    141         LOG(VB_COMMFLAG, LOG_INFO, "Analyzing edge data");
    142 
    143 #ifdef SHOW_DEBUG_WIN
    144         unsigned char *fakeFrame;
    145         fakeFrame = new unsigned char[width * height * 3 / 2];
    146         memset(fakeFrame, 0, width * height * 3 / 2);
    147 #endif
    148 
    149         for (y = 0; y < height; y++)
    150         {
    151             if ((y > (height/4)) && (y < (height * 3 / 4)))
    152                 continue;
    153 
    154             for (x = 0; x < width; x++)
    155             {
    156                 if ((x > (width/4)) && (x < (width * 3 / 4)))
    157                     continue;
    158 
    159                 pos = y * width + x;
    160 
    161                 if (edgeCounts[pos].isedge > (maxLoops * 0.66))
    162                 {
    163                     edgeMask[pos].isedge = 1;
    164                     pixelsInMask++;
    165 #ifdef SHOW_DEBUG_WIN
    166                     fakeFrame[pos] = 0xff;
    167 #endif
    168 
    169                 }
    170 
    171                 if (edgeCounts[pos].horiz > (maxLoops * 0.66))
    172                     edgeMask[pos].horiz = 1;
    173 
    174                 if (edgeCounts[pos].vert > (maxLoops * 0.66))
    175                     edgeMask[pos].vert = 1;
    176 
    177                 if (edgeCounts[pos].ldiag > (maxLoops * 0.66))
    178                     edgeMask[pos].ldiag = 1;
    179                 if (edgeCounts[pos].rdiag > (maxLoops * 0.66))
    180                     edgeMask[pos].rdiag = 1;
    181             }
    182         }
    183 
    184         SetLogoMaskArea();
    185 
    186         for (y = logoMinY; y < logoMaxY; y++)
    187         {
    188             for (x = logoMinX; x < logoMaxX; x++)
    189             {
    190                 int neighbors = 0;
    191 
    192                 if (!edgeMask[y * width + x].isedge)
    193                     continue;
    194 
    195                 for (dy = y - 2; dy <= (y + 2); dy++ )
    196                 {
    197                     for (dx = x - 2; dx <= (x + 2); dx++ )
    198                     {
    199                         if (edgeMask[dy * width + dx].isedge)
    200                             neighbors++;
    201                     }
    202                 }
    203 
    204                 if (neighbors < 5)
    205                     edgeMask[y * width + x].isedge = 0;
    206             }
    207103        }
     104       
     105        player->DiscardVideoFrame(player->GetRawVideoFrame(0));
    208106
    209         SetLogoMaskArea();
     107        pixelsInMask = AnalyzeEdgeCounts(edgeCounts, maxLoops * 2 / 3);
     108       
    210109        LOG(VB_COMMFLAG, LOG_INFO,
    211             QString("Testing Logo area: topleft (%1,%2), bottomright (%3,%4)")
     110            QString("Testing Logo area: topleft (%1,%2), size (%3,%4)")
    212111                .arg(logoMinX).arg(logoMinY)
    213                 .arg(logoMaxX).arg(logoMaxY));
    214 
    215 #ifdef SHOW_DEBUG_WIN
    216         for (x = logoMinX; x < logoMaxX; x++)
    217         {
    218             pos = logoMinY * width + x;
    219             fakeFrame[pos] = 0x7f;
    220             pos = logoMaxY * width + x;
    221             fakeFrame[pos] = 0x7f;
    222         }
    223         for (y = logoMinY; y < logoMaxY; y++)
    224         {
    225             pos = y * width + logoMinX;
    226             fakeFrame[pos] = 0x7f;
    227             pos = y * width + logoMaxX;
    228             fakeFrame[pos] = 0x7f;
    229         }
    230 
    231         comm_debug_show(fakeFrame);
    232         delete [] fakeFrame;
     112                .arg(logoWidth).arg(logoHeight));
    233113
    234         cerr << "Hit ENTER to continue" << endl;
    235         getchar();
    236 #endif
    237         if (((logoMaxX - logoMinX) < (width / 4)) &&
    238             ((logoMaxY - logoMinY) < (height / 4)) &&
    239             (pixelsInMask > 50))
     114        if (pixelsInMask > 100 &&
     115            (logoWidth < (width / 6) || logoHeight < (height / 6)))
    240116        {
    241117            logoInfoAvailable = true;
    242118            logoEdgeDiff = edgeDiffs[i];
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    245121                QString("Using Logo area: topleft (%1,%2), "
    246122                        "bottomright (%3,%4)")
    247123                    .arg(logoMinX).arg(logoMinY)
    248                     .arg(logoMaxX).arg(logoMaxY));
     124                    .arg(logoWidth).arg(logoHeight));
    249125        }
    250126        else
    251127        {
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    254130                        "bottomright (%3,%4), pixelsInMask (%5). "
    255131                        "Not within specified limits.")
    256132                    .arg(logoMinX).arg(logoMinY)
    257                     .arg(logoMaxX).arg(logoMaxY)
     133                    .arg(logoWidth).arg(logoHeight)
    258134                    .arg(pixelsInMask));
    259135        }
    260136    }
    bool ClassicLogoDetector::searchForLogo(MythPlayer* player) 
    263139
    264140    if (!logoInfoAvailable)
    265141        LOG(VB_COMMFLAG, LOG_NOTICE, "No suitable logo area found.");
    266 
    267     player->DiscardVideoFrame(player->GetRawVideoFrame(0));
     142    else
     143        DumpLogo();
     144   
    268145    return logoInfoAvailable;
    269146}
    270147
    271 
    272 void ClassicLogoDetector::SetLogoMaskArea()
     148int ClassicLogoDetector::AnalyzeEdgeCounts(int *edgeCounts, int threshold)
    273149{
    274     LOG(VB_COMMFLAG, LOG_INFO, "SetLogoMaskArea()");
    275 
     150    const int minNeighbors = 2;
     151    int pixelsInMask = 0;
     152    unsigned int logoMaxX = 0, logoMaxY = 0;
     153   
    276154    logoMinX = width - 1;
    277     logoMaxX = 0;
    278155    logoMinY = height - 1;
    279     logoMaxY = 0;
    280 
     156   
     157    LOG(VB_COMMFLAG, LOG_INFO, "Analyzing edge data");
     158   
     159    QBitArray tmpMask(width*height);
     160   
    281161    for (unsigned int y = 0; y < height; y++)
    282162    {
    283163        for (unsigned int x = 0; x < width; x++)
    284164        {
    285             if (edgeMask[y * width + x].isedge)
     165            unsigned int pos = y * width + x;
     166            if (edgeCounts[pos] < threshold)
     167                continue;
     168           
     169            int neighbors = 0;
     170           
     171            // 3x3 block
     172            for (int dy = y - 1; dy <= (y + 1); dy++)
     173            {
     174                for (int dx = x - 1; dx <= (x + 1); dx++)
     175                {
     176                    unsigned int dp = dy * width + dx;
     177                    if (edgeCounts[dp] >= threshold)
     178                    {
     179                        neighbors++;
     180                        if (neighbors > minNeighbors)
     181                            break;
     182                    }
     183                }
     184            }
     185           
     186            if (neighbors > minNeighbors)
    286187            {
     188                tmpMask[pos] = true;
     189               
     190                pixelsInMask++;
     191               
    287192                if (x < logoMinX)
    288193                    logoMinX = x;
    289194                if (y < logoMinY)
    void ClassicLogoDetector::SetLogoMaskArea() 
    293198                if (y > logoMaxY)
    294199                    logoMaxY = y;
    295200            }
    296         }
    297     }
    298 
    299     logoMinX -= 5;
    300     logoMaxX += 5;
    301     logoMinY -= 5;
    302     logoMaxY += 5;
    303 
    304     if (logoMinX < 4)
    305         logoMinX = 4;
    306     if (logoMaxX > (width-5))
    307         logoMaxX = (width-5);
    308     if (logoMinY < 4)
    309         logoMinY = 4;
    310     if (logoMaxY > (height-5))
    311         logoMaxY = (height-5);
    312 }
    313 
    314 void ClassicLogoDetector::SetLogoMask(unsigned char *mask)
    315 {
    316     int pixels = 0;
    317 
    318     memcpy(logoMask, mask, width * height);
    319 
    320     SetLogoMaskArea();
    321 
    322     for(unsigned int y = logoMinY; y <= logoMaxY; y++)
    323         for(unsigned int x = logoMinX; x <= logoMaxX; x++)
    324             if (!logoMask[y * width + x] == 1)
    325                 pixels++;
    326 
    327     if (pixels < 30)
    328         return;
    329 
    330     // set the pixels around our logo
    331     for(unsigned int y = (logoMinY - 1); y <= (logoMaxY + 1); y++)
    332     {
    333         for(unsigned int x = (logoMinX - 1); x <= (logoMaxX + 1); x++)
    334         {
    335             if (!logoMask[y * width + x])
     201            else
    336202            {
    337                 for (unsigned int y2 = y - 1; y2 <= (y + 1); y2++)
    338                 {
    339                     for (unsigned int x2 = x - 1; x2 <= (x + 1); x2++)
    340                     {
    341                         if ((logoMask[y2 * width + x2] == 1) &&
    342                             (!logoMask[y * width + x]))
    343                         {
    344                             logoMask[y * width + x] = 2;
    345                             x2 = x + 2;
    346                             y2 = y + 2;
    347 
    348                             logoCheckMask[y2 * width + x2] = 1;
    349                             logoCheckMask[y * width + x] = 1;
    350                         }
    351                     }
    352                 }
     203                tmpMask[pos] = false;
    353204            }
    354         }
    355     }
    356 
    357     for(unsigned int y = (logoMinY - 2); y <= (logoMaxY + 2); y++)
     205        } // end for x
     206    } // end for y
     207   
     208    logoMinX -= 1;
     209    logoMaxX += 1;
     210    logoMinY -= 1;
     211    logoMaxY += 1;
     212
     213    if (logoMinX < commDetectBorder)
     214        logoMinX = commDetectBorder;
     215    if (logoMaxX > (width-commDetectBorder))
     216        logoMaxX = (width-commDetectBorder);
     217    if (logoMinY < commDetectBorder)
     218        logoMinY = commDetectBorder;
     219    if (logoMaxY > (height-commDetectBorder))
     220        logoMaxY = (height-commDetectBorder);
     221   
     222    if (pixelsInMask > 0 && logoMaxX > logoMinX && logoMaxY > logoMinY)
    358223    {
    359         for(unsigned int x = (logoMinX - 2); x <= (logoMaxX + 2); x++)
     224        logoWidth = logoMaxX - logoMinX;
     225        logoHeight = logoMaxY - logoMinY;
     226       
     227        edgeMask.resize(logoWidth * logoHeight);
     228        for (unsigned int y = 0; y < logoHeight; ++y)
    360229        {
    361             if (!logoMask[y * width + x])
     230            for (unsigned int x = 0; x < logoWidth; ++x)
    362231            {
    363                 for (unsigned int y2 = y - 1; y2 <= (y + 1); y2++)
    364                 {
    365                     for (unsigned int x2 = x - 1; x2 <= (x + 1); x2++)
    366                     {
    367                         if ((logoMask[y2 * width + x2] == 2) &&
    368                             (!logoMask[y * width + x]))
    369                         {
    370                             logoMask[y * width + x] = 3;
    371                             x2 = x + 2;
    372                             y2 = y + 2;
    373 
    374                             logoCheckMask[y * width + x] = 1;
    375                         }
    376                     }
    377                 }
     232                edgeMask[y * logoWidth + x] = tmpMask[(y + logoMinY) * width + (x + logoMinX)];
    378233            }
    379234        }
    380235    }
    381 
    382 #ifdef SHOW_DEBUG_WIN
    383     DumpLogo(true,framePtr);
    384 #endif
    385 
    386     logoFrameCount = 0;
    387     logoInfoAvailable = true;
     236   
     237    return pixelsInMask;
    388238}
    389239
    390 
    391 void ClassicLogoDetector::DumpLogo(bool fromCurrentFrame,
    392     unsigned char* framePtr)
     240void ClassicLogoDetector::DumpLogo()
    393241{
    394     char scrPixels[] = " .oxX";
    395 
    396     if (!logoInfoAvailable)
    397         return;
    398 
    399     cerr << "\nLogo Data ";
    400     if (fromCurrentFrame)
    401         cerr << "from current frame\n";
    402 
    403     cerr << "\n     ";
    404 
    405     for(unsigned int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
    406         cerr << (x % 10);
    407     cerr << "\n";
    408 
    409     for(unsigned int y = logoMinY - 2; y <= (logoMaxY + 2); y++)
     242    cerr << "Logo data (" << logoMinX << "," << logoMinY << ") x ("
     243                          << logoWidth << "," << logoHeight << ") @ "
     244                          << logoEdgeDiff << ":\n";
     245   
     246    for (unsigned int y = 0; y < logoHeight; y++)
    410247    {
    411         QString tmp = QString("%1: ").arg(y, 3);
    412         QString ba = tmp.toAscii();
    413         cerr << ba.constData();
    414         for(unsigned int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
     248        for (unsigned int x = 0; x < logoWidth; x++)
    415249        {
    416             if (fromCurrentFrame)
    417             {
    418                 cerr << scrPixels[framePtr[y * width + x] / 50];
    419             }
     250            unsigned int pos = y * logoWidth + x;
     251            if (edgeMask[pos])
     252                cerr << "#";
    420253            else
    421             {
    422                 switch (logoMask[y * width + x])
    423                 {
    424                         case 0:
    425                         case 2: cerr << " ";
    426                         break;
    427                         case 1: cerr << "*";
    428                         break;
    429                         case 3: cerr << ".";
    430                         break;
    431                 }
    432             }
     254                cerr << " ";
    433255        }
    434256        cerr << "\n";
    435257    }
    436     cerr.flush();
     258   
     259    cerr << "\n\n\n";
    437260}
    438261
     262bool ClassicLogoDetector::pixelInsideLogo(unsigned int x, unsigned int y)
     263{
     264    if (!logoInfoAvailable)
     265        return false;
     266   
     267    int xd = x - logoMinX;
     268    int yd = y - logoMinY;
     269   
     270    return xd >= 0 && xd < (int)logoWidth &&
     271           yd >= 0 && yd < (int)logoHeight;
     272}
    439273
    440 /* ideas for this method ported back from comskip.c mods by Jere Jones
    441  * which are partially mods based on Myth's original commercial skip
    442  * code written by Chris Pinkham. */
    443 bool ClassicLogoDetector::doesThisFrameContainTheFoundLogo(
    444     unsigned char* framePtr)
     274bool ClassicLogoDetector::isSobelEdgeAt(unsigned char *buf,
     275                                        unsigned int x,
     276                                        unsigned int y,
     277                                        unsigned int width,
     278                                        unsigned char edgeDiff)
    445279{
    446     int radius = 2;
    447     unsigned int x, y;
    448     int pos1, pos2, pos3;
    449     int pixel;
    450     int goodEdges = 0;
    451     int badEdges = 0;
    452     int testEdges = 0;
    453     int testNotEdges = 0;
     280    int center = y * width + x;
     281    int above = center - width;
     282    int below = center + width;
     283   
     284    int gx = 0;
     285    gx -= buf[above - 1];
     286    gx -= (buf[center - 1]*2);
     287    gx -= buf[below - 1];
     288   
     289    gx += buf[above + 1];
     290    gx += (buf[center + 1]*2);
     291    gx += buf[below + 1];
     292   
     293    int gy = 0;
     294    gy -= buf[above - 1];
     295    gy -= (buf[above]*2);
     296    gy -= buf[above + 1];
     297   
     298    gy += buf[below - 1];
     299    gy += (buf[below]*2);
     300    gy += buf[below + 1];
     301   
     302    return abs(gx) + abs(gy) > 3*edgeDiff;
     303}
    454304
    455     for (y = logoMinY; y <= logoMaxY; y++ )
     305bool ClassicLogoDetector::doesThisFrameContainTheFoundLogo(unsigned char *framePtr)
     306{
     307    if (!logoInfoAvailable)
     308        return false;
     309   
     310    unsigned int x, y;
     311    unsigned int correct = 0, total = 0;
     312   
     313    for (y = 0; y < logoHeight; y++ )
    456314    {
    457         for (x = logoMinX; x <= logoMaxX; x++ )
     315        for (x = 0; x < logoWidth; x++ )
    458316        {
    459             pos1 = y * width + x;
    460             pos2 = (y - radius) * width + x;
    461             pos3 = (y + radius) * width + x;
    462 
    463             pixel = framePtr[pos1];
    464 
    465             if (edgeMask[pos1].horiz)
    466             {
    467                 if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
    468                     (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
    469                     goodEdges++;
    470                 testEdges++;
    471             }
    472             else
    473             {
    474                 if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
    475                     (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
    476                     badEdges++;
    477                 testNotEdges++;
    478             }
    479 
    480             if (edgeMask[pos1].vert)
    481             {
    482                 if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
    483                     (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
    484                     goodEdges++;
    485                 testEdges++;
    486             }
    487             else
     317            if (edgeMask[y * logoWidth + x])
    488318            {
    489                 if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
    490                     (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
    491                     badEdges++;
    492                 testNotEdges++;
     319                if (isSobelEdgeAt(framePtr, x + logoMinX, y + logoMinY, width, logoEdgeDiff))
     320                    correct++;
     321                total ++;
    493322            }
    494323        }
    495324    }
    496 
    497     frameNumber++;
    498     double goodEdgeRatio = (double)goodEdges / (double)testEdges;
    499     double badEdgeRatio = (double)badEdges / (double)testNotEdges;
    500     if ((goodEdgeRatio > commDetectLogoGoodEdgeThreshold) &&
    501         (badEdgeRatio < commDetectLogoBadEdgeThreshold))
    502         return true;
    503     else
    504         return false;
    505 }
    506 
    507 bool ClassicLogoDetector::pixelInsideLogo(unsigned int x, unsigned int y)
    508 {
    509     if (!logoInfoAvailable)
    510         return false;
    511 
    512     return ((x > logoMinX) && (x < logoMaxX) &&
    513             (y > logoMinY) && (y < logoMaxY));
     325   
     326    double d = (double)correct / (double)total;
     327    return d >= commDetectLogoGoodEdgeThreshold;
    514328}
    515329
    516 void ClassicLogoDetector::DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges,
    517                                       int edgeDiff)
     330void ClassicLogoDetector::DetectEdges(VideoFrame *frame, int *edgeCounts, int edgeDiff)
    518331{
    519     int r = 2;
    520     unsigned char *buf = frame->buf;
    521     unsigned char p;
    522     unsigned int pos, x, y;
    523 
    524     for (y = commDetectBorder + r; y < (height - commDetectBorder - r); y++)
     332    unsigned int x, y;
     333   
     334    unsigned int hOneThird = height / 3;
     335    unsigned int hTwoThirds = hOneThird*2;
     336    unsigned int wOneThird = width / 3;
     337    unsigned int wTwoThirds = wOneThird*2;
     338   
     339    for (y = commDetectBorder; y < height - commDetectBorder; ++y)
    525340    {
    526         if ((y > (height/4)) && (y < (height * 3 / 4)))
    527             continue;
    528 
    529         for (x = commDetectBorder + r; x < (width - commDetectBorder - r); x++)
     341        for (x = commDetectBorder; x < width - commDetectBorder; ++x)
    530342        {
    531             int edgeCount = 0;
    532 
    533             if ((x > (width/4)) && (x < (width * 3 / 4)))
    534                 continue;
    535 
    536             pos = y * width + x;
    537             p = buf[pos];
    538 
    539             if (( abs(buf[y * width + (x - r)] - p) >= edgeDiff) ||
    540                 ( abs(buf[y * width + (x + r)] - p) >= edgeDiff))
    541             {
    542                 edges[pos].horiz++;
    543                 edgeCount++;
    544             }
    545             if (( abs(buf[(y - r) * width + x] - p) >= edgeDiff) ||
    546                 ( abs(buf[(y + r) * width + x] - p) >= edgeDiff))
    547             {
    548                 edges[pos].vert++;
    549                 edgeCount++;
    550             }
    551 
    552             if (( abs(buf[(y - r) * width + (x - r)] - p) >= edgeDiff) ||
    553                 ( abs(buf[(y + r) * width + (x + r)] - p) >= edgeDiff))
     343            if (y > hOneThird && y < hTwoThirds &&
     344                x > wOneThird && x < wTwoThirds)
    554345            {
    555                 edges[pos].ldiag++;
    556                 edgeCount++;
     346                x = wTwoThirds - 1;
    557347            }
    558 
    559             if (( abs(buf[(y - r) * width + (x + r)] - p) >= edgeDiff) ||
    560                 ( abs(buf[(y + r) * width + (x - r)] - p) >= edgeDiff))
     348            else if (isSobelEdgeAt(frame->buf, x, y, width, edgeDiff))
    561349            {
    562                 edges[pos].rdiag++;
    563                 edgeCount++;
     350                edgeCounts[y * width + x]++;
    564351            }
    565 
    566             if (edgeCount >= 3)
    567                 edges[pos].isedge++;
    568352        }
    569353    }
    570354}
    571355
    572356/* vim: set expandtab tabstop=4 shiftwidth=4: */
    573 
  • mythtv/programs/mythcommflag/ClassicLogoDetector.h

    diff --git a/mythtv/programs/mythcommflag/ClassicLogoDetector.h b/mythtv/programs/mythcommflag/ClassicLogoDetector.h
    index d589df5..a78ce4c 100644
    a b  
    22#define _CLASSICLOGOGEDETECTOR_H_
    33
    44#include "LogoDetectorBase.h"
     5#include <qbitarray.h>
    56
    6 typedef struct edgemaskentry EdgeMaskEntry;
    77typedef struct VideoFrame_ VideoFrame;
    88class ClassicCommDetector;
    99
    class ClassicLogoDetector : public LogoDetectorBase 
    1616    virtual void deleteLater(void);
    1717
    1818    bool searchForLogo(MythPlayer* player);
    19     bool doesThisFrameContainTheFoundLogo(unsigned char* frame);
     19    bool doesThisFrameContainTheFoundLogo(unsigned char *framePtr);
    2020    bool pixelInsideLogo(unsigned int x, unsigned int y);
    2121
    2222    unsigned int getRequiredAvailableBufferForSearch();
    2323
     24    void DumpLogo();
     25    static bool isSobelEdgeAt(unsigned char *buf, unsigned int x, unsigned int y, unsigned int width, unsigned char edgeDiff);
     26   
    2427  protected:
    2528    virtual ~ClassicLogoDetector() {}
    2629
    2730  private:
    28     void SetLogoMaskArea();
    29     void SetLogoMask(unsigned char *mask);
    30     void DumpLogo(bool fromCurrentFrame,unsigned char* framePtr);
    31     void DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges, int edgeDiff);
    32 
     31    int AnalyzeEdgeCounts(int *edgeCounts, int threshold);
     32    void DetectEdges(VideoFrame *frame, int *edgeCounts, int edgeDiff);
     33   
    3334    ClassicCommDetector* commDetector;
    34     unsigned int frameNumber;
    35     bool previousFrameWasSceneChange;
    36     unsigned int xspacing, yspacing;
    3735    unsigned int commDetectBorder;
    38 
     36   
    3937    int commDetectLogoSamplesNeeded;
    4038    int commDetectLogoSampleSpacing;
    4139    int commDetectLogoSecondsNeeded;
    4240    double commDetectLogoGoodEdgeThreshold;
    4341    double commDetectLogoBadEdgeThreshold;
     42   
     43    QBitArray edgeMask;
    4444
    45     EdgeMaskEntry *edgeMask;
    46 
    47     unsigned char *logoMaxValues;
    48     unsigned char *logoMinValues;
    49     unsigned char *logoFrame;
    50     unsigned char *logoMask;
    51     unsigned char *logoCheckMask;
    52     unsigned char *tmpBuf;
    53 
     45    bool logoInfoAvailable;   
    5446    int logoEdgeDiff;
    55     unsigned int logoFrameCount;
    5647    unsigned int logoMinX;
    57     unsigned int logoMaxX;
     48    unsigned int logoWidth;
    5849    unsigned int logoMinY;
    59     unsigned int logoMaxY;
    60 
    61     bool logoInfoAvailable;
     50    unsigned int logoHeight;
    6251};
    6352
    6453#endif
  • mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp

    diff --git a/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp b/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp
    index c449353..ff096a5 100644
    a b using namespace std; 
    66
    77ClassicSceneChangeDetector::ClassicSceneChangeDetector(unsigned int width,
    88        unsigned int height, unsigned int commdetectborder_in,
    9         unsigned int xspacing_in, unsigned int yspacing_in):
     9        unsigned int fps_in):
    1010    SceneChangeDetectorBase(width,height),
    11     frameNumber(0),
    12     previousFrameWasSceneChange(false),
    13     xspacing(xspacing_in),
    14     yspacing(yspacing_in),
    15     commdetectborder(commdetectborder_in)
     11    commdetectborder(commdetectborder_in),
     12    fps(fps_in),
     13    prevSceneEnd(0),
     14    thisSceneStart(0)
    1615{
    1716    histogram = new Histogram;
    1817    previousHistogram = new Histogram;
     18    previousSceneHistogram = new Histogram;
    1919}
    2020
    2121void ClassicSceneChangeDetector::deleteLater(void)
    2222{
    2323    delete histogram;
    2424    delete previousHistogram;
     25    delete previousSceneHistogram;
    2526    SceneChangeDetectorBase::deleteLater();
    2627}
    2728
    28 void ClassicSceneChangeDetector::processFrame(unsigned char* frame)
     29void ClassicSceneChangeDetector::processFrame(unsigned int frameNumber, unsigned char* frame)
    2930{
    3031    histogram->generateFromImage(frame, width, height, commdetectborder,
    3132                                 width-commdetectborder, commdetectborder,
    32                                  height-commdetectborder, xspacing, yspacing);
     33                                 height-commdetectborder, 1, 1);
    3334    float similar = histogram->calculateSimilarityWith(*previousHistogram);
    3435
    35     bool isSceneChange = (similar < .85 && !previousFrameWasSceneChange);
    36 
    37     emit(haveNewInformation(frameNumber,isSceneChange,similar));
    38     previousFrameWasSceneChange = isSceneChange;
    39 
    40     std::swap(histogram,previousHistogram);
    41     frameNumber++;
     36    bool isSceneChange = similar < .85;
     37    if (isSceneChange)
     38    {
     39        // If the last scene was recent we can consider it
     40        if (frameNumber - prevSceneEnd <= fps * 30)
     41        {
     42            float prevSim = histogram->calculateSimilarityWith(*previousSceneHistogram);
     43            if (prevSim >= 0.85)
     44            {
     45                // If this scene looks the same as the previous scene then there was no change
     46                isSceneChange = false;
     47               
     48                // Undo what we previously said was a scene change
     49                emit(haveNewInformation(prevSceneEnd, false, 1.25));
     50            }
     51        }
     52       
     53        if (frameNumber - thisSceneStart <= fps / 8)
     54        {
     55            // Supress change flags on rapidly changing scenery
     56            isSceneChange = false;
     57        }
     58        else
     59        {
     60            std::swap(previousSceneHistogram, previousHistogram);
     61            prevSceneEnd = thisSceneStart;
     62            thisSceneStart = frameNumber;
     63        }
     64    }
     65    std::swap(previousHistogram,histogram);
     66   
     67    emit(haveNewInformation(frameNumber, isSceneChange, similar));
    4268}
    4369
    4470/* vim: set expandtab tabstop=4 shiftwidth=4: */
    45 
  • mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h

    diff --git a/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h b/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h
    index f4d2200..43a9687 100644
    a b class ClassicSceneChangeDetector : public SceneChangeDetectorBase 
    99{
    1010  public:
    1111    ClassicSceneChangeDetector(unsigned int width, unsigned int height,
    12         unsigned int commdetectborder, unsigned int xspacing,
    13         unsigned int yspacing);
     12        unsigned int commdetectborder, unsigned int fps);
    1413    virtual void deleteLater(void);
    1514
    16     void processFrame(unsigned char* frame);
     15    void processFrame(unsigned int frameNumber, unsigned char* frame);
    1716
    1817  private:
    1918    ~ClassicSceneChangeDetector() {}
    class ClassicSceneChangeDetector : public SceneChangeDetectorBase 
    2120  private:
    2221    Histogram* histogram;
    2322    Histogram* previousHistogram;
    24     unsigned int frameNumber;
    25     bool previousFrameWasSceneChange;
    26     unsigned int xspacing, yspacing;
     23    Histogram* previousSceneHistogram;
    2724    unsigned int commdetectborder;
     25    unsigned int fps;
     26    unsigned int prevSceneEnd, thisSceneStart;
    2827};
    2928
    3029#endif
  • mythtv/programs/mythcommflag/Histogram.cpp

    diff --git a/mythtv/programs/mythcommflag/Histogram.cpp b/mythtv/programs/mythcommflag/Histogram.cpp
    index 12d2a9a..849f23b 100644
    a b unsigned int Histogram::getThresholdForPercentageOfPixels(float percentage) 
    7070
    7171float Histogram::calculateSimilarityWith(const Histogram& other) const
    7272{
    73     long similar = 0;
    74 
    75     for(unsigned int i = 0; i < 256; i++)
     73    const int proximity = 5;
     74    long similarity = 0;
     75
     76    similarity += std::min(data[0],
     77                           other.data[0]);
     78    similarity += std::min(data[0] + data[1],
     79                           other.data[0] + other.data[1]);
     80    similarity += std::min(data[0] + data[1] + data[2],
     81                           other.data[0] + other.data[1] + other.data[2]);
     82   
     83    for(unsigned int i = 0; i <= 256 - proximity; i++)
    7684    {
    77         if (data[i] < other.data[i])
    78             similar += data[i];
    79         else
    80             similar += other.data[i];
     85        unsigned int mine = 0, others = 0;
     86        for (int j = 0; j < proximity; ++j)
     87        {
     88            mine += data[i+j];
     89            others += other.data[i+j];
     90        }
     91        similarity += std::min(mine, others);
    8192    }
    82 
    83     //Using c style cast for old gcc compatibility.
    84     return static_cast<float>(similar) / static_cast<float>(numberOfSamples);
     93   
     94    similarity += std::min(data[253] + data[254] + data[255],
     95                           other.data[253] + other.data[254] + other.data[255]);
     96    similarity += std::min(data[254] + data[255],
     97                           other.data[254] + other.data[255]);
     98    similarity += std::min(data[255],
     99                           other.data[255]);
     100   
     101    return similarity / static_cast<float>(numberOfSamples * proximity);
    85102}
    86103
    87104/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythtv/programs/mythcommflag/SceneChangeDetectorBase.h

    diff --git a/mythtv/programs/mythcommflag/SceneChangeDetectorBase.h b/mythtv/programs/mythcommflag/SceneChangeDetectorBase.h
    index 67296d5..338c80a 100644
    a b class SceneChangeDetectorBase : public QObject 
    1111    SceneChangeDetectorBase(unsigned int w, unsigned int h) :
    1212        width(w), height(h) {}
    1313
    14     virtual void processFrame(unsigned char *frame) = 0;
     14    virtual void processFrame(unsigned int frameNumber, unsigned char *frame) = 0;
    1515
    1616  signals:
    1717    void haveNewInformation(unsigned int framenum, bool scenechange,
  • mythtv/programs/mythcommflag/main.cpp

    diff --git a/mythtv/programs/mythcommflag/main.cpp b/mythtv/programs/mythcommflag/main.cpp
    index 5c03c1d..0bc7e13 100644
    a b static int FlagCommercials(ProgramInfo *program_info, int jobid, 
    735735    int breaksFound = 0;
    736736
    737737    // configure commercial detection method
    738     SkipTypes commDetectMethod =
    739             (enum SkipTypes)gCoreContext->GetNumSetting(
     738    SkipTypes commDetectMethod = (SkipTypes)gCoreContext->GetNumSetting(
    740739                                    "CommercialSkipMethod", COMM_DETECT_ALL);
    741740
    742741    if (cmdline.toBool("commmethod"))
    static int FlagCommercials(ProgramInfo *program_info, int jobid, 
    750749        if (!ok)
    751750        {
    752751            // not an integer, attempt comma separated list
    753             commDetectMethod = COMM_DETECT_UNINIT;
     752            commDetectMethod = COMM_DETECT_OFF;
    754753            QMap<QString, SkipTypes>::const_iterator sit;
    755754
    756755            QStringList list = commmethod.split(",", QString::SkipEmptyParts);
    static int FlagCommercials(ProgramInfo *program_info, int jobid, 
    774773
    775774                // append flag method to list
    776775                commDetectMethod = (SkipTypes) ((int)commDetectMethod
    777                                              || (int)skipTypes->value(val));
     776                                                | (int)skipTypes->value(val));
    778777            }
    779 
    780778        }
    781779        if (commDetectMethod == COMM_DETECT_UNINIT)
    782780            return GENERIC_EXIT_INVALID_CMDLINE;
    783781    }
    784     else if (!cmdline.toBool("skipdb"))
     782    else if (useDB)
    785783    {
    786784        // if not manually specified, and we have a database to access
    787785        // pull the commflag type from the channel
    static int FlagCommercials(ProgramInfo *program_info, int jobid, 
    819817                QString("Using method: %1 from channel %2")
    820818                    .arg(commDetectMethod).arg(program_info->GetChanID()));
    821819        }
    822 
    823820    }
    824     else if (cmdline.toBool("skipdb"))
    825         // default to a cheaper method for debugging purposes
    826         commDetectMethod = COMM_DETECT_BLANK;
    827821
    828822    // if selection has failed, or intentionally disabled, drop out
    829823    if (commDetectMethod == COMM_DETECT_UNINIT)
    int main(int argc, char *argv[]) 
    11431137    cmdline.ApplySettingsOverride();
    11441138
    11451139    MythTranslation::load("mythfrontend");
    1146 
     1140   
     1141    if (cmdline.toBool("outputmethod"))
     1142    {
     1143        QString om = cmdline.toString("outputmethod");
     1144        if (outputTypes->contains(om))
     1145            outputMethod = outputTypes->value(om);
     1146    }
     1147   
    11471148    if (cmdline.toBool("chanid") && cmdline.toBool("starttime"))
    11481149    {
    11491150        // operate on a recording in the database