[mythtv] [PATCH] Add AFD support for aspect 'magic'

Neale Swinnerton mythtv-dev.spam at isismanor.com
Sat Jun 4 14:16:03 UTC 2005


The Active Format Descriptor (AFD) is set by some broadcasters like ITV1
and CH4 in the UK in their DVB-T streams. This signals what the format
of the video is, and along with the aspect ratio of the video stream and
your display it can resize the video 'better'.

This patch adds support for this to myth. To enable it go to
Utilities/Setup->Settings->TV Settings->Playback and set aspect override
to AFD.

When playing back streams that have AFD set you should see the image
scaled better. ie. it will apply letterboxing/pillarboxing as
appropriate, Shoot & Protect areas should be honoured.

AFD has some caveats:
	+ Only works where the MPEG Stream is either 4:3 or 16:9
	+ Only works where your display is either 4:3 or 16:9

Note that if you don't have GuiSizeForTv set the aspect ratio comes from
the DisplaySize option in your xorg.conf, if GuiSizeForTv is set myth
calculates the aspect ratio of your screen with the following code

void VideoOutputXv::InitDisplayMeasurements(uint width, uint height)
{
 <SNIP/>
        int w = DisplayWidth(XJ_disp, XJ_screen_num);
        int h = DisplayHeight(XJ_disp, XJ_screen_num);
        int gui_w = w, gui_h = h;
        gContext->GetResolutionSetting("Gui", gui_w,  gui_h);
        if (gui_w)
            w_mm = w_mm * gui_w / w;
        if (gui_h)
            h_mm = h_mm * gui_h / h;

        display_aspect = (float)w_mm/h_mm;
<SNIP/>
}

w_mm/h_mm is the width/height of your screen in mm as reported by X (ie.
the values passed via DisplaySize option), for me this means I need a
gui size of 1024x576 to get my display aspect to 1.78.

I left debug output switched on in the patch, so you will see what value
myth is calculating for your aspect ratio....

TODO: I'm not sure that the size calculations for the various
combinations are correct, it seems to work for my limited testing on
ITV1 / Ch 4. I'm trying to find a test stream to test this out.

http://www.rsd.de/www/dev_center.nsf/frameset?OpenAgent&website=com&content=/www/dev_center.nsf/html/DV-TCMuseafd

looks ideal, but I don't have access to that sort of kit and I haven't
found an easy way to generate such a stream. Any ideas?

TODO: It seems reasonable to add a 'AFD or Fill' mode that falls back to
Fill Mode if the AFD isn't set. This should be easy, but the code needs
a rejig to allow the fill code to be common to both modes.

TODO: Implement WSS line 23 switching in the Unichrome driver, to make
this really slick. I doubt this is easily possible, maybe some boards
support it (
http://www.commell.com.tw/Product/Peripheral/MiniAGP/MA-HDTV.htm )

enjoy...

Neale.


-------------- next part --------------
diff -bBuwr mythtv-20050530/libs/libmythtv/NuppelVideoPlayer.cpp mythtv-20050530.patched/libs/libmythtv/NuppelVideoPlayer.cpp
--- mythtv-20050530/libs/libmythtv/NuppelVideoPlayer.cpp	2005-05-24 03:59:13.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/NuppelVideoPlayer.cpp	2005-06-02 22:37:21.000000000 +0100
@@ -455,6 +455,7 @@
 
     videofiltersLock.lock();
     videoOutput->InputChanged(video_width, video_height, video_aspect);
+    videoOutput->SetAfdMode(video_afd_mode);
     if (videoOutput->IsErrored())
     {
         VERBOSE(VB_IMPORTANT, "ReinitVideo(): videoOutput->IsErrored()");
@@ -531,13 +532,13 @@
 
 void NuppelVideoPlayer::SetVideoParams(int width, int height, double fps,
                                        int keyframedistance, float aspect,
-                                       FrameScanType scan, bool reinit)
+                                       int afd_mode, FrameScanType scan, bool reinit)
 {
     if (width == 0 || height == 0 || isnan(aspect) || isnan(fps))
         return;
 
     if (video_width == width && video_height == height && 
-        aspect == video_aspect && fps == video_frame_rate)
+        aspect == video_aspect && afd_mode == video_afd_mode && fps == video_frame_rate)
     {
         return;
     }
@@ -564,6 +565,8 @@
             commDetect->SetVideoParams(aspect);
     }
 
+    video_afd_mode = afd_mode;
+
     if (reinit)
         ReinitVideo();
 
diff -bBuwr mythtv-20050530/libs/libmythtv/NuppelVideoPlayer.h mythtv-20050530.patched/libs/libmythtv/NuppelVideoPlayer.h
--- mythtv-20050530/libs/libmythtv/NuppelVideoPlayer.h	2005-05-05 03:51:15.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/NuppelVideoPlayer.h	2005-06-02 22:36:30.000000000 +0100
@@ -156,7 +156,8 @@
     void SetKeyframeDistance(int keyframedistance);
     void SetVideoParams(int width, int height, double fps,
                         int keyframedistance, float aspect = 1.33333,
-                        FrameScanType scan = kScan_Ignore, bool reinit = false);
+                        int afd_code = kAfd_Unset, FrameScanType scan = kScan_Ignore, 
+                        bool reinit = false);
     void SetAudioParams(int bps, int channels, int samplerate);
     void SetEffDsp(int dsprate);
     void SetFileLength(int total, int frames);
@@ -295,6 +296,7 @@
     int video_size;
     double video_frame_rate;
     float video_aspect;
+    int video_afd_mode;
     FrameScanType m_scan;
     bool m_double_framerate;
     bool m_can_double;
diff -bBuwr mythtv-20050530/libs/libmythtv/avformatdecoder.cpp mythtv-20050530.patched/libs/libmythtv/avformatdecoder.cpp
--- mythtv-20050530/libs/libmythtv/avformatdecoder.cpp	2005-05-23 21:39:12.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/avformatdecoder.cpp	2005-06-03 07:19:11.000000000 +0100
@@ -553,6 +553,7 @@
     current_width = enc->width;
     current_height = enc->height;
     current_aspect = aspect_ratio;
+    current_afd_mode = enc->dtg_active_format;
 
     enc->opaque = NULL;
     enc->get_buffer = NULL;
@@ -603,7 +604,7 @@
         avcodec_align_dimensions(enc, &align_width, &align_height);
 
     m_parent->SetVideoParams(align_width, align_height, fps,
-                             keyframedist, aspect_ratio, kScan_Detect);
+                             keyframedist, aspect_ratio, current_afd_mode, kScan_Detect);
 }
 
 #ifdef USING_XVMC
@@ -1158,10 +1159,12 @@
 
                     float aspect = GetMpegAspect(context, aspectratioinfo,
                                                  width, height);
+		    int afd_mode = context->dtg_active_format;
 
                     if (width < 2500 && height < 2000 &&
                         (CheckVideoParams(width, height) ||
-                         aspect != current_aspect))
+                         aspect != current_aspect ||
+			 afd_mode != current_afd_mode))
                     {
                         int align_width = width;
                         int align_height = height;
@@ -1174,11 +1177,12 @@
 
                         m_parent->SetVideoParams(align_width,
                                                  align_height, fps,
-                                                 keyframedist, aspect, 
+                                                 keyframedist, aspect, afd_mode,
                                                  kScan_Detect, true);
                         current_width = width;
                         current_height = height;
                         current_aspect = aspect;
+			current_afd_mode = afd_mode;
 
                         if (d->mpeg2dec)
                             d->ResetMPEG2();
diff -bBuwr mythtv-20050530/libs/libmythtv/decoderbase.h mythtv-20050530.patched/libs/libmythtv/decoderbase.h
--- mythtv-20050530/libs/libmythtv/decoderbase.h	2005-04-27 20:32:49.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/decoderbase.h	2005-06-03 07:16:20.000000000 +0100
@@ -87,6 +87,7 @@
     int current_width;
     int current_height;
     float current_aspect;
+    int current_afd_mode;
 
     long long framesPlayed;
     long long framesRead;
diff -bBuwr mythtv-20050530/libs/libmythtv/tv_play.cpp mythtv-20050530.patched/libs/libmythtv/tv_play.cpp
--- mythtv-20050530/libs/libmythtv/tv_play.cpp	2005-05-27 01:59:21.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/tv_play.cpp	2005-06-02 22:09:40.000000000 +0100
@@ -3476,6 +3476,7 @@
         case kLetterbox_16_9_Zoom:    text = tr("16:9 Zoom"); break;
         case kLetterbox_16_9_Stretch: text = tr("16:9 Stretch"); break;
         case kLetterbox_Fill:         text = tr("Fill"); break;
+        case kLetterbox_Afd:          text = tr("Active Format"); break;
         default:                      text = tr("Off"); break;
     }
 
diff -bBuwr mythtv-20050530/libs/libmythtv/videooutbase.cpp mythtv-20050530.patched/libs/libmythtv/videooutbase.cpp
--- mythtv-20050530/libs/libmythtv/videooutbase.cpp	2005-05-26 03:17:04.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/videooutbase.cpp	2005-06-04 01:09:38.365803256 +0100
@@ -136,6 +136,7 @@
 VideoOutput::VideoOutput()
 {
     letterbox = kLetterbox_Off;
+    afd_mode = kAfd_Unset;
 
     framesPlayed = 0;
 
@@ -359,7 +360,8 @@
     {
         default:
         case kLetterbox_Off:
-        case kLetterbox_Fill:           XJ_aspect = videoAspect;
+        case kLetterbox_Fill:           
+        case kLetterbox_Afd:            XJ_aspect = videoAspect;
                                         break;
 
         case kLetterbox_4_3:
@@ -487,6 +489,9 @@
     yoff   = imgy;
     width  = imgw;
     height = imgh;
+    float displayAspect = GetDisplayAspect();
+    bool displayAspectIs_16_9 = (fabs(displayAspect - 1.777777) < 0.05);
+    bool videoAspectIs_16_9 = (fabs(XJ_aspect - 1.777777) < 0.05);
 
     switch (letterbox)
     {
@@ -504,19 +509,68 @@
         case kLetterbox_Fill:
             if (GetDisplayAspect() > XJ_aspect)
             {
-                int pixDisplayed = int(((XJ_aspect / GetDisplayAspect()) * imgh) + 0.5);
+                int pixDisplayed = int(((XJ_aspect /displayAspect) * imgh) + 0.5);
 
                 height = pixDisplayed;
                 yoff = (imgh - pixDisplayed) / 2;
             }
             else
             {
-                int pixDisplayed = int(((GetDisplayAspect() / XJ_aspect) * imgw) + 0.5);
+                int pixDisplayed = int(((displayAspect / XJ_aspect) * imgw) + 0.5);
 
                 width = pixDisplayed;
                 xoff = (imgw - pixDisplayed) / 2;
             }
             break;
+        case kLetterbox_Afd:
+         if ( videoAspectIs_16_9 ) {
+             switch (afd_mode)
+             {
+                 case kAfd_Unset:
+                 case kAfd_Same:
+                 case kAfd_16_9:
+                 case kAfd_14_9:
+                 case kAfd_16_9_Sp_14_9:
+                 case kAfd_Sp_4_3:
+                         break;
+                 case kAfd_4_3:
+                     if (displayAspectIs_16_9) {
+                            width *= 3/4;
+                            xoff = width/6;
+                     }
+                     break;
+                 case kAfd_4_3_Sp_14_9:
+                     if (displayAspectIs_16_9) {
+			    height *= 4/3; 
+                            yoff -= height/6;
+                            width *= 3/4;
+                            xoff += width/6;
+                     }
+                     break;
+             }
+         } else { // videoAspectIs_4_3
+             switch (afd_mode)
+             {
+                 case kAfd_Unset:
+                 case kAfd_16_9:
+                 case kAfd_16_9_Sp_14_9:
+                     break;
+                 case kAfd_Same:
+                 case kAfd_Sp_4_3:
+                     if (displayAspectIs_16_9) {
+                            width *=  3/4;
+                            xoff  += width/6;
+		     }
+		     break;
+                 case kAfd_4_3_Sp_14_9:
+                     if (displayAspectIs_16_9) {
+                            width = width*4/3;
+                            yoff -= height/6;
+                     }
+                     break;
+             }
+         }
+            break;
         default:
             break;
     }
@@ -532,6 +586,7 @@
 {
     int yoff, xoff;
     float displayAspect;
+    int displayAspectIs_16_9, videoAspectIs_16_9;
 
     // Preset all image placement and sizing variables.
     imgx = 0; imgy = 0;
@@ -544,6 +599,8 @@
 
     // Get display aspect and correct for rounding errors
     displayAspect = GetDisplayAspect();
+    displayAspectIs_16_9 = (fabs(displayAspect - 1.777777) > 0.05)?0:1;
+    videoAspectIs_16_9 = (fabs(XJ_aspect - 1.333333) > 0.05)?0:1;
 
     // Check if close to 4:3
     if(fabs(displayAspect - 1.333333) < 0.05)
@@ -659,11 +716,61 @@
     // account the aspect ratios of both the video as well as the actual
     // screen to allow proper letterboxing to take place.
     
-    //cout << "XJ aspect " << XJ_aspect << endl;
-    //cout << "Display aspect " << GetDisplayAspect() << endl;
-    //printf("Before: %dx%d%+d%+d\n", dispwoff, disphoff, dispxoff, 
-    //    dispyoff);
-    
+    cout << "XJ aspect " << XJ_aspect << endl;
+    cout << "Display aspect " << GetDisplayAspect() << endl;
+    cout << "AFD " << afd_mode << endl;
+    printf("Before: %dx%d%+d%+d\n", dispwoff, disphoff, dispxoff, 
+        dispyoff);
+    
+    if ( letterbox == kLetterbox_Afd ){
+         if ( videoAspectIs_16_9 ) {
+             switch (afd_mode)
+             {
+                 case kAfd_Unset:
+                 case kAfd_Same:
+                 case kAfd_16_9:
+                 case kAfd_14_9:
+                 case kAfd_16_9_Sp_14_9:
+                 case kAfd_Sp_4_3:
+                         break;
+                 case kAfd_4_3:
+                     if (displayAspectIs_16_9) {
+                            dispwoff =  dispwoff*3/4;
+                            dispxoff += (dispwoff/6);
+                     }
+                     break;
+                 case kAfd_4_3_Sp_14_9:
+                     if (displayAspectIs_16_9) {
+                            disphoff = disphoff*4/3;
+                            dispyoff -= (disphoff/6);
+                            dispwoff = (dispwoff*3/4);
+                            dispxoff += (dispwoff/6);
+                     }
+                     break;
+             }
+         } else { // videoAspectIs_4_3
+             switch (afd_mode)
+             {
+                 case kAfd_Unset:
+                 case kAfd_16_9:
+                 case kAfd_16_9_Sp_14_9:
+                     break;
+                 case kAfd_Same:
+                 case kAfd_Sp_4_3:
+                     if (displayAspectIs_16_9) {
+                            dispwoff =  dispwoff*3/4;
+                            dispxoff += (dispwoff/6);
+		     }
+		     break;
+                 case kAfd_4_3_Sp_14_9:
+                     if (displayAspectIs_16_9) {
+                            dispyoff -= (disphoff/6);
+                            disphoff = disphoff*4/3;
+                     }
+                     break;
+             }
+         }
+    }
     if ((fabs(displayAspect - XJ_aspect) / displayAspect) > 0.1){
         if(letterbox == kLetterbox_Fill){
             if (displayAspect > XJ_aspect)
@@ -772,7 +880,6 @@
     //printf("After: %dx%d%+d%+d\n", dispwoff, disphoff, dispxoff, 
     //dispyoff);
 
-#if 0
     printf("VideoOutput::MoveResize:\n");
     printf("Img(%d,%d %d,%d)\n", imgx, imgy, imgw, imgh);
     printf("Disp(%d,%d %d,%d)\n", dispxoff, dispyoff, dispwoff, disphoff);
@@ -783,7 +890,6 @@
     printf("XJ_aspect(%f)\n", XJ_aspect);
     printf("CDisplayAspect: %f\n", displayAspect);
     printf("Letterbox: %d\n", letterbox);
-#endif
  
     VERBOSE(VB_PLAYBACK,
             QString("Image size. dispxoff %1, dispyoff: %2, dispwoff: %3, "
diff -bBuwr mythtv-20050530/libs/libmythtv/videooutbase.h mythtv-20050530.patched/libs/libmythtv/videooutbase.h
--- mythtv-20050530/libs/libmythtv/videooutbase.h	2005-05-26 03:17:04.000000000 +0100
+++ mythtv-20050530.patched/libs/libmythtv/videooutbase.h	2005-06-04 00:36:13.000000000 +0100
@@ -105,9 +105,29 @@
     kLetterbox_16_9_Zoom,
     kLetterbox_16_9_Stretch,
     kLetterbox_Fill,
+    kLetterbox_Afd,
     kLetterbox_END
 };
 
+/* Active Format Description(AFD) is set in DVB Streams.
+ * By considering both the aspect ratio and the AFD it 
+ * is posible to determine how to present the image in the
+ * correct manner. 
+ * See http://www.dtg.org.uk/publications/books/afd.pdf
+ * for the gory details
+ */
+enum AfdMode {
+    kAfd_Unset        = 0,
+    kAfd_Same         = 8,
+    kAfd_4_3          = 9,
+    kAfd_16_9         = 10,
+    kAfd_14_9         = 11,
+    kAfd_4_3_Sp_14_9  = 13,
+    kAfd_16_9_Sp_14_9 = 14,
+    kAfd_Sp_4_3       = 15,
+    kAfd_END
+};
+
 enum FrameScanType {
     kScan_Ignore      = -1,
     kScan_Progressive =  0,
@@ -162,6 +182,8 @@
     int GetLetterbox(void) { return letterbox; }
     void ToggleLetterbox(int letterboxMode = kLetterbox_Toggle);
 
+    void SetAfdMode(int afd_mode) { this->afd_mode = afd_mode; };
+    
     // pass in null to use the pause frame, if it exists.
     virtual void ProcessFrame(VideoFrame *frame, OSD *osd,
                               FilterChain *filterList,
@@ -298,6 +321,7 @@
     int brightness, contrast, colour, hue;
 
     int letterbox;
+    int afd_mode;
 
     int PIPLocation;
 
diff -bBuwr mythtv-20050530/programs/mythfrontend/globalsettings.cpp mythtv-20050530.patched/programs/mythfrontend/globalsettings.cpp
--- mythtv-20050530/programs/mythfrontend/globalsettings.cpp	2005-05-28 01:48:30.000000000 +0100
+++ mythtv-20050530.patched/programs/mythfrontend/globalsettings.cpp	2005-06-04 01:14:06.980231084 +0100
@@ -1160,11 +1160,15 @@
     gc->addSelection(QObject::tr("16/9 Zoom"), "4");
     gc->addSelection(QObject::tr("16/9 Stretch"), "5");
     gc->addSelection(QObject::tr("Fill"), "6");
+    gc->addSelection(QObject::tr("AFD"), "7");
     gc->setHelpText(QObject::tr("This will override any aspect ratio in the "
                     "recorded stream, the same as pressing the W Key "
                     "during playback. "
 		    "Fill will \"fill\" the screen with the image clipping as required. "
 		    "Fill is useful when using 4:3 interlaced TV's for display."
+                    "AFD will use the active format descriptor from the stream "
+		    "to determine the appropriate display. "
+		    "(UK ITV & Ch4 only?)"
 		    ));
     return gc;
 }


More information about the mythtv-dev mailing list