]> granicus.if.org Git - handbrake/commitdiff
Add WebM support (#1822)
authorJustin Bull <me@justinbull.ca>
Wed, 13 Feb 2019 14:52:48 +0000 (09:52 -0500)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Wed, 13 Feb 2019 14:52:48 +0000 (06:52 -0800)
Note that since webm has no official subtitle support, only burned in subtitles can be used with this muxer at this time.

31 files changed:
gtk/src/callbacks.c
gtk/src/ghb.m4
gtk/src/hb-backend.c
gtk/src/main.c
libhb/common.c
libhb/common.h
libhb/decavcodec.c
libhb/internal.h
libhb/muxavformat.c
libhb/muxcommon.c
macosx/HBAudioTrack.m
macosx/HBJob+UIAdditions.m
macosx/HBPreviewGenerator.m
macosx/HBVideo.m
macosx/HandBrakeKit/de.lproj/Localizable.strings
win/CS/HandBrake.Interop/Interop/Model/Encoding/Container.cs
win/CS/HandBrakeWPF/Converters/Audio/AudioEncoderConverter.cs
win/CS/HandBrakeWPF/Converters/Video/VideoEncoderConverter.cs
win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs
win/CS/HandBrakeWPF/Properties/Resources.Designer.cs
win/CS/HandBrakeWPF/Properties/Resources.resx
win/CS/HandBrakeWPF/Services/Encode/Model/Models/OutputFormat.cs
win/CS/HandBrakeWPF/ViewModels/AudioViewModel.cs
win/CS/HandBrakeWPF/ViewModels/Interfaces/ISubtitlesViewModel.cs
win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs
win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs
win/CS/HandBrakeWPF/ViewModels/SubtitlesViewModel.cs
win/CS/HandBrakeWPF/ViewModels/SummaryViewModel.cs
win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs
win/CS/HandBrakeWPF/Views/SubtitlesView.xaml
win/CS/HandBrakeWPF/Views/SummaryView.xaml

index 60e4a2b1a7e40fc8e729f984da609789abd03853..f8614d13c8690ca70f53d81bfc44a81cc28a9e28 100644 (file)
@@ -1934,7 +1934,7 @@ dvd_source_activate_cb(GtkWidget *widget, signal_user_data_t *ud)
 void
 ghb_update_destination_extension(signal_user_data_t *ud)
 {
-    static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".error", NULL};
+    static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".webm", ".error", NULL};
     gchar *filename;
     const gchar *extension;
     gint ii;
index d9dea4c8ad5af58fd7264e9db09c466005d4afd3..108a89aefe907fa89a6a7e723ce853c8f23409b6 100644 (file)
@@ -16,6 +16,7 @@ filter_output([
   <object class="GtkFileFilter" id="SourceFilterEVO"/>
   <object class="GtkFileFilter" id="SourceFilterFLV"/>
   <object class="GtkFileFilter" id="SourceFilterMKV"/>
+  <object class="GtkFileFilter" id="SourceFilterWebM"/>
   <object class="GtkFileFilter" id="SourceFilterMOV"/>
   <object class="GtkFileFilter" id="SourceFilterMP4"/>
   <object class="GtkFileFilter" id="SourceFilterMPG"/>
index e433d50dea382d26459f9338d1f1414b6d55a16c..a638487f6831227bc34ddbe20b75c36a29e4cd20 100644 (file)
@@ -4298,6 +4298,8 @@ ghb_validate_video(GhbValue *settings, GtkWindow *parent)
     mux_id = ghb_dict_get_string(settings, "FileFormat");
     mux = ghb_lookup_container_by_name(mux_id);
 
+    gboolean v_unsup = FALSE;
+
     vcodec = ghb_settings_video_encoder_codec(settings, "VideoEncoder");
     if ((mux->format & HB_MUX_MASK_MP4) && (vcodec == HB_VCODEC_THEORA))
     {
@@ -4306,6 +4308,21 @@ ghb_validate_video(GhbValue *settings, GtkWindow *parent)
                     _("Theora is not supported in the MP4 container.\n\n"
                     "You should choose a different video codec or container.\n"
                     "If you continue, FFMPEG will be chosen for you."));
+        v_unsup = TRUE;
+    }
+    else if ((mux->format & HB_MUX_MASK_WEBM) &&
+             (vcodec != HB_VCODEC_FFMPEG_VP8 && vcodec != HB_VCODEC_FFMPEG_VP9))
+    {
+        // webm only supports vp8 and vp9.
+        message = g_strdup_printf(
+                    _("Only VP8 or VP9 is supported in the WebM container.\n\n"
+                    "You should choose a different video codec or container.\n"
+                    "If you continue, one will be chosen for you."));
+        v_unsup = TRUE;
+    }
+
+    if (v_unsup)
+    {
         if (!ghb_message_dialog(parent, GTK_MESSAGE_WARNING,
                                 message, _("Cancel"), _("Continue")))
         {
@@ -4317,6 +4334,7 @@ ghb_validate_video(GhbValue *settings, GtkWindow *parent)
         ghb_dict_set_string(settings, "VideoEncoder",
                                 hb_video_encoder_get_short_name(vcodec));
     }
+
     return TRUE;
 }
 
@@ -4340,6 +4358,12 @@ ghb_validate_subtitles(GhbValue *settings, GtkWindow *parent)
     gint count, ii, track;
     gboolean burned, one_burned = FALSE;
 
+    const char *mux_id;
+    const hb_container_t *mux;
+
+    mux_id = ghb_dict_get_string(settings, "FileFormat");
+    mux = ghb_lookup_container_by_name(mux_id);
+
     slist = ghb_get_job_subtitle_list(settings);
     count = ghb_array_len(slist);
     for (ii = 0; ii < count; ii++)
@@ -4369,6 +4393,22 @@ ghb_validate_subtitles(GhbValue *settings, GtkWindow *parent)
         {
             one_burned = TRUE;
         }
+        else if (mux->format & HB_MUX_MASK_WEBM)
+        {
+            // WebM can only handle burned subs afaik. Their specs are ambiguous here
+            message = g_strdup_printf(
+            _("WebM in HandBrake only supports burned subtitles.\n\n"
+                "You should change your subtitle selections.\n"
+                "If you continue, some subtitles will be lost."));
+            if (!ghb_message_dialog(parent, GTK_MESSAGE_WARNING,
+                                    message, _("Cancel"), _("Continue")))
+            {
+                g_free(message);
+                return FALSE;
+            }
+            g_free(message);
+            break;
+        }
         if (import != NULL)
         {
             const gchar *filename;
@@ -4457,6 +4497,10 @@ ghb_validate_audio(GhbValue *settings, GtkWindow *parent)
             {
                 codec = HB_ACODEC_LAME;
             }
+            else if (mux->format & HB_MUX_MASK_WEBM)
+            {
+                codec = hb_audio_encoder_get_default(mux->format);
+            }
             else
             {
                 codec = HB_ACODEC_FFAAC;
@@ -4464,8 +4508,8 @@ ghb_validate_audio(GhbValue *settings, GtkWindow *parent)
             const char *name = hb_audio_encoder_get_short_name(codec);
             ghb_dict_set_string(asettings, "Encoder", name);
         }
-        gchar *a_unsup = NULL;
-        gchar *mux_s = NULL;
+        const gchar *a_unsup = NULL;
+        const gchar *mux_s = NULL;
         if (mux->format & HB_MUX_MASK_MP4)
         {
             mux_s = "MP4";
@@ -4476,6 +4520,16 @@ ghb_validate_audio(GhbValue *settings, GtkWindow *parent)
                 codec = HB_ACODEC_FFAAC;
             }
         }
+        if (mux->format & HB_MUX_MASK_WEBM)
+        {
+            mux_s = "WebM";
+            // WebM only supports Vorbis and Opus codecs
+            if (codec != HB_ACODEC_VORBIS && codec != HB_ACODEC_OPUS)
+            {
+                a_unsup = hb_audio_encoder_get_short_name(codec);
+                codec = hb_audio_encoder_get_default(mux->format);
+            }
+        }
         if (a_unsup)
         {
             message = g_strdup_printf(
index e8236066839b12a7cb6623197bd3d8bc7810c5df..dd86cf242f225f78b6c95ceb1f6490b6034b3ce7 100644 (file)
@@ -1126,6 +1126,7 @@ ghb_activate_cb(GApplication * app, signal_user_data_t * ud)
         SourceFilterEVO
         SourceFilterVOB
         SourceFilterMKV
+        SourceFilterWebM
         SourceFilterMP4
         SourceFilterAVI
         SourceFilterMOV
@@ -1174,6 +1175,10 @@ ghb_activate_cb(GApplication * app, signal_user_data_t * ud)
     gtk_file_filter_add_pattern(filter, "*.mkv");
     gtk_file_filter_add_pattern(filter, "*.MKV");
     gtk_file_chooser_add_filter(chooser, filter);
+    filter = GTK_FILE_FILTER(GHB_OBJECT(ud->builder, "SourceFilterWebM"));
+    gtk_file_filter_set_name(filter, "WebM");
+    gtk_file_filter_add_pattern(filter, "*.webm");
+    gtk_file_chooser_add_filter(chooser, filter);
     filter = GTK_FILE_FILTER(GHB_OBJECT(ud->builder, "SourceFilterMP4"));
     gtk_file_filter_set_name(filter, "MP4");
     gtk_file_filter_add_pattern(filter, "*.mp4");
index 26e7ff02a75722830d5f43948fcde4ffc0414da5..7e3636d1416ef58cfd3ac277898bfd418efe9fe4 100644 (file)
@@ -80,6 +80,7 @@ enum
     HB_GID_ACODEC_OPUS,
     HB_GID_MUX_MKV,
     HB_GID_MUX_MP4,
+    HB_GID_MUX_WEBM,
 };
 
 #define HB_VIDEO_CLOCK    27000000 // 27MHz clock
@@ -265,8 +266,8 @@ hb_encoder_internal_t hb_video_encoders[]  =
     { { "H.265 (VideoToolbox)","vt_h265",    "H.265 (libavcodec)",      HB_VCODEC_FFMPEG_VT_H265,    HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H265,   },
     { { "MPEG-4",              "mpeg4",      "MPEG-4 (libavcodec)",     HB_VCODEC_FFMPEG_MPEG4,      HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4,  },
     { { "MPEG-2",              "mpeg2",      "MPEG-2 (libavcodec)",     HB_VCODEC_FFMPEG_MPEG2,      HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2,  },
-    { { "VP8",                 "VP8",        "VP8 (libvpx)",            HB_VCODEC_FFMPEG_VP8,                        HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_VP8,    },
-    { { "VP9",                 "VP9",        "VP9 (libvpx)",            HB_VCODEC_FFMPEG_VP9,                        HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_VP9,    },
+    { { "VP8",                 "VP8",        "VP8 (libvpx)",            HB_VCODEC_FFMPEG_VP8,       HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_VP8,    },
+    { { "VP9",                 "VP9",        "VP9 (libvpx)",            HB_VCODEC_FFMPEG_VP9,       HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_VP9,    },
     { { "Theora",              "theora",     "Theora (libtheora)",      HB_VCODEC_THEORA,                            HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_THEORA, },
 };
 int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_video_encoders[0]);
@@ -375,11 +376,11 @@ hb_encoder_internal_t hb_audio_encoders[]  =
     { { "DTS-HD Passthru",    "copy:dtshd", "DTS-HD Passthru",             HB_ACODEC_DCA_HD_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_DTSHD_PASS, },
     { { "MP3",                "mp3",        "MP3 (libmp3lame)",            HB_ACODEC_LAME,        HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3,        },
     { { "MP3 Passthru",       "copy:mp3",   "MP3 Passthru",                HB_ACODEC_MP3_PASS,    HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3_PASS,   },
-    { { "Vorbis",             "vorbis",     "Vorbis (libvorbis)",          HB_ACODEC_VORBIS,                      HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_VORBIS,     },
+    { { "Vorbis",             "vorbis",     "Vorbis (libvorbis)",          HB_ACODEC_VORBIS,     HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_VORBIS,     },
     { { "FLAC 16-bit",        "flac16",     "FLAC 16-bit (libavcodec)",    HB_ACODEC_FFFLAC,                      HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC,       },
     { { "FLAC 24-bit",        "flac24",     "FLAC 24-bit (libavcodec)",    HB_ACODEC_FFFLAC24,                    HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC,       },
     { { "FLAC Passthru",      "copy:flac",  "FLAC Passthru",               HB_ACODEC_FLAC_PASS,                   HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC_PASS,  },
-    { { "Opus",               "opus",     "Opus (libopus)",                HB_ACODEC_OPUS,                        HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_OPUS,     },
+    { { "Opus",               "opus",     "Opus (libopus)",                HB_ACODEC_OPUS,       HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_OPUS,     },
     { { "Auto Passthru",      "copy",       "Auto Passthru",               HB_ACODEC_AUTO_PASS,   HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AUTO_PASS,  },
 };
 int hb_audio_encoders_count = sizeof(hb_audio_encoders) / sizeof(hb_audio_encoders[0]);
@@ -443,14 +444,15 @@ hb_container_t *hb_containers_last_item  = NULL;
 hb_container_internal_t hb_containers[]  =
 {
     // legacy muxers, back to HB 0.9.4 whenever possible (disabled)
-    { { "M4V file",            "m4v",    NULL,                     "m4v",  0,             }, NULL, 0, HB_GID_MUX_MP4, },
-    { { "MP4 file",            "mp4",    NULL,                     "mp4",  0,             }, NULL, 0, HB_GID_MUX_MP4, },
-    { { "MKV file",            "mkv",    NULL,                     "mkv",  0,             }, NULL, 0, HB_GID_MUX_MKV, },
+    { { "M4V file",            "m4v",     NULL,                     "m4v",  0,              }, NULL, 0, HB_GID_MUX_MP4,  },
+    { { "MP4 file",            "mp4",     NULL,                     "mp4",  0,              }, NULL, 0, HB_GID_MUX_MP4,  },
+    { { "MKV file",            "mkv",     NULL,                     "mkv",  0,              }, NULL, 0, HB_GID_MUX_MKV,  },
     // actual muxers
-    { { "MPEG-4 (avformat)",   "av_mp4", "MPEG-4 (libavformat)",   "mp4",  HB_MUX_AV_MP4, }, NULL, 1, HB_GID_MUX_MP4, },
-    { { "MPEG-4 (mp4v2)",      "mp4v2",  "MPEG-4 (libmp4v2)",      "mp4",  HB_MUX_MP4V2,  }, NULL, 1, HB_GID_MUX_MP4, },
-    { { "Matroska (avformat)", "av_mkv", "Matroska (libavformat)", "mkv",  HB_MUX_AV_MKV, }, NULL, 1, HB_GID_MUX_MKV, },
-    { { "Matroska (libmkv)",   "libmkv", "Matroska (libmkv)",      "mkv",  HB_MUX_LIBMKV, }, NULL, 1, HB_GID_MUX_MKV, },
+    { { "MPEG-4 (avformat)",   "av_mp4",  "MPEG-4 (libavformat)",   "mp4",  HB_MUX_AV_MP4,  }, NULL, 1, HB_GID_MUX_MP4,  },
+    { { "MPEG-4 (mp4v2)",      "mp4v2",   "MPEG-4 (libmp4v2)",      "mp4",  HB_MUX_MP4V2,   }, NULL, 1, HB_GID_MUX_MP4,  },
+    { { "Matroska (avformat)", "av_mkv",  "Matroska (libavformat)", "mkv",  HB_MUX_AV_MKV,  }, NULL, 1, HB_GID_MUX_MKV,  },
+    { { "Matroska (libmkv)",   "libmkv",  "Matroska (libmkv)",      "mkv",  HB_MUX_LIBMKV,  }, NULL, 1, HB_GID_MUX_MKV,  },
+    { { "WebM (avformat)",     "av_webm", "WebM (libavformat)",     "webm", HB_MUX_AV_WEBM, }, NULL, 1, HB_GID_MUX_WEBM, },
 };
 int hb_containers_count = sizeof(hb_containers) / sizeof(hb_containers[0]);
 static int hb_container_is_enabled(int format)
@@ -459,6 +461,7 @@ static int hb_container_is_enabled(int format)
     {
         case HB_MUX_AV_MP4:
         case HB_MUX_AV_MKV:
+        case HB_MUX_AV_WEBM:
             return 1;
 
         default:
@@ -4961,6 +4964,10 @@ int hb_subtitle_can_pass( int source, int mux )
                     return 0;
             } break;
 
+        // webm can't support subtitles unless they're burned.
+        // there's ambiguity in the spec about WebVTT... TODO
+        case HB_MUX_AV_WEBM:
+            return 0;
         default:
             // Internal error. Should never get here.
             hb_error("internal error.  Bad mux %d\n", mux);
index 0e1da879453eb793681185d032f23d7fb4348974..2d332d7feaa086230efec210bc4d4db8cdf516b5 100644 (file)
@@ -606,18 +606,22 @@ struct hb_job_s
      *     mux:  output file format
      *     file: file path
      */
-#define HB_MUX_MASK     0xFF0001
-#define HB_MUX_INVALID  0x000000
-#define HB_MUX_MP4V2    0x010000
-#define HB_MUX_AV_MP4   0x020000
-#define HB_MUX_MASK_MP4 0x030000
-#define HB_MUX_LIBMKV   0x100000
-#define HB_MUX_AV_MKV   0x200000
-#define HB_MUX_MASK_MKV 0x300000
-#define HB_MUX_MASK_AV  0x220000
+#define HB_MUX_MASK      0xFF0001
+#define HB_MUX_INVALID   0x000000
+#define HB_MUX_MP4V2     0x010000
+#define HB_MUX_AV_MP4    0x020000
+#define HB_MUX_MASK_MP4  0x030000
+#define HB_MUX_LIBMKV    0x100000
+#define HB_MUX_AV_MKV    0x200000
+#define HB_MUX_AV_WEBM   0x400000
+#define HB_MUX_MASK_MKV  0x300000
+#define HB_MUX_MASK_AV   0x620000
+#define HB_MUX_MASK_WEBM 0x400000
+
 /* default muxer for each container */
-#define HB_MUX_MP4      HB_MUX_AV_MP4
-#define HB_MUX_MKV      HB_MUX_AV_MKV
+#define HB_MUX_MP4       HB_MUX_AV_MP4
+#define HB_MUX_MKV       HB_MUX_AV_MKV
+#define HB_MUX_WEBM      HB_MUX_AV_WEBM
 
     int             mux;
     char          * file;
index 957e2ae754e1f7adee272893b8590f9116dd9573..e9bf81a1d1c5c27cae6821fd02b3b4847cf46fad 100644 (file)
@@ -853,7 +853,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
                     {
                         // Parse ADTS AAC streams for AudioSpecificConfig.
                         // This data is required in order to write
-                        // proper headers in MP4 and MKV files.
+                        // proper headers in MP4, WebM, and MKV files.
                         parse_adts_extradata(audio, context, &avp);
                     }
 
index 1284a1ff0c3defc03bcbff5b56d17268c6a5aa73..8983a13cdfb17013f97640291d219620457a6409 100644 (file)
@@ -493,6 +493,7 @@ typedef struct hb_mux_data_s   hb_mux_data_t;
 
 DECLARE_MUX( mp4 );
 DECLARE_MUX( mkv );
+DECLARE_MUX( webm );
 DECLARE_MUX( avformat );
 
 void hb_deinterlace(hb_buffer_t *dst, hb_buffer_t *src);
index 2d4390f53128b309ac9289631597d8313f6f86e9..40df89c8ed310b0307c4c71752111012488d9b4e 100644 (file)
@@ -70,6 +70,7 @@ enum
 {
     META_MUX_MP4,
     META_MUX_MKV,
+    META_MUX_WEBM,
     META_MUX_LAST
 };
 
@@ -98,6 +99,7 @@ static char* lookup_lang_code(int mux, char *iso639_2)
             out = iso639_2;
             break;
         case HB_MUX_AV_MKV:
+        case HB_MUX_AV_WEBM: // webm is a subset of mkv
             // MKV lang codes should be ISO-639-2B if it exists,
             // else ISO-639-2
             lang =  lang_for_code2( iso639_2 );
@@ -164,6 +166,15 @@ static int avformatInit( hb_mux_object_t * m )
             meta_mux = META_MUX_MKV;
             break;
 
+        case HB_MUX_AV_WEBM:
+            // libavformat is essentially hard coded such that it only
+            // works with a timebase of 1/1000
+            m->time_base.num = 1;
+            m->time_base.den = 1000;
+            muxer_name = "webm";
+            meta_mux = META_MUX_WEBM;
+            break;
+
         default:
         {
             hb_error("Invalid Mux %x", job->mux);
@@ -1184,7 +1195,8 @@ static int avformatMux(hb_mux_object_t *m, hb_mux_data_t *track, hb_buffer_t *bu
         return 0;
     }
 
-    if (track->type == MUX_TYPE_VIDEO && (job->mux & HB_MUX_MASK_MKV) &&
+    if (track->type == MUX_TYPE_VIDEO &&
+        (job->mux & (HB_MUX_MASK_MKV | HB_MUX_MASK_WEBM)) &&
         buf->s.renderOffset < 0)
     {
         // libav matroska muxer doesn't write dts to the output, but
index 5034b32e3a6a540ffc4d5f2a8fa1210a59935f35..93b144a23221a47aeab96254559f2b325acf3817 100644 (file)
@@ -611,6 +611,7 @@ static int muxInit( hb_work_object_t * muxer, hb_job_t * job )
         {
             case HB_MUX_AV_MP4:
             case HB_MUX_AV_MKV:
+            case HB_MUX_AV_WEBM:
                 mux->m = hb_mux_avformat_init( job );
                 break;
             default:
index a77305cf4d2af2b7e3bf5f79fb1f4c053f721ed1..fd7865646474789014a4ad4bb48e326579f59bdc 100644 (file)
@@ -251,7 +251,7 @@ NSString *keyAudioTrackLanguageIsoCode = @"keyAudioTrackLanguageIsoCode";
             }
         }
 
-        return HB_ACODEC_CA_AAC;
+        return hb_audio_encoder_get_default(self.container);
     }
     else
     {
index 4c1cdc8ae1be9f9680b7476b1927a6d78833be75..56c721271da718d46c93ba6fb0fcda2a1542f9ea 100644 (file)
@@ -78,6 +78,10 @@ static NSDictionary            *shortHeightAttr;
         {
             title = HBKitLocalizedString(@"MKV File", @"HBJob -> Format display name");
         }
+        else if (container->format & HB_MUX_MASK_WEBM)
+        {
+            title = HBKitLocalizedString(@"WebM File", @"HBJob -> Format display name");
+        }
         else
         {
             title = @(container->name);
@@ -922,6 +926,10 @@ static NSDictionary            *shortHeightAttr;
     {
         return HBKitLocalizedString(@"MKV File", @"HBJob -> Format display name");
     }
+    else if (container & HB_MUX_MASK_WEBM)
+    {
+        return HBKitLocalizedString(@"WebM File", @"HBJob -> Format display name");
+    }
     else
     {
         const char *name = hb_container_get_name(container);
@@ -951,6 +959,10 @@ static NSDictionary            *shortHeightAttr;
     {
         return @(HB_MUX_AV_MKV);
     }
+    else if ([value isEqualToString:HBKitLocalizedString(@"WebM File", @"HBJob -> Format display name")])
+    {
+        return @(HB_MUX_AV_WEBM);
+    }
 
     return @(hb_container_get_from_name([value UTF8String]));
 }
index efc95e011173489eaea35402317e1ef3fd357e79..dde0ccd32055c0d2a6a8064e9ad56a44732e28af 100644 (file)
     {
         destURL = [HBPreviewGenerator generateFileURLForType:@"mkv"];
     }
+    else if (self.job.container & 0x400000 /*HB_MUX_MASK_WEBM*/)
+    {
+        destURL = [HBPreviewGenerator generateFileURLForType:@"webm"];
+    }
 
     // return if we couldn't get the fileURL.
     if (!destURL)
index a1fb9bd71cc76569ed3130e04e5c3af6fc679434..bf8c00d67e394fb2eab14589a07ea8b0733d1d99 100644 (file)
@@ -202,7 +202,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
 
     if (!encoderSupported)
     {
-        self.encoder = HB_VCODEC_X264;
+        self.encoder = hb_video_encoder_get_default(self.job.container);
     }
 }
 
index d3a9eb993af9649f707e0878e38822d79502541f..5506abf4c019e953d595b58c387e0ea12e139366 100644 (file)
 /* HBJob -> Format display name */
 "MKV File" = "MKV-Datei";
 
+/* HBJob -> Format display name */
+"WebM File" = "WebM-Datei";
+
 /* HBJob -> Format display name */
 "MP4 File" = "MP4-Datei";
 
index 8950d2b92d1460fde81e9ee62cfd4931218d86aa..9ceeb61320ca5a85e5ad7e2efb464cc3089e7a5e 100644 (file)
@@ -24,6 +24,8 @@ namespace HandBrake.Interop.Interop.Model.Encoding
         [DisplayName("MP4")]
         MP4,
         [DisplayName("MKV")]
-        MKV
+        MKV,
+        [DisplayName("WebM")]
+        WebM
     }
 }
index 7216c6fe439e6374b30f786ef9620560a6d962e7..cc317c14c0d14a12b1916bc7da113439c190da71 100644 (file)
@@ -64,7 +64,7 @@ namespace HandBrakeWPF.Converters.Audio
                     encoders.Remove(AudioEncoder.fdkheaac);\r
                 }\r
 \r
-                if (task != null && task.OutputFormat != OutputFormat.Mkv)\r
+                if (task != null && task.OutputFormat == OutputFormat.Mp4)\r
                 {\r
                     encoders.Remove(AudioEncoder.Vorbis);\r
                     encoders.Remove(AudioEncoder.ffflac);\r
@@ -74,6 +74,10 @@ namespace HandBrakeWPF.Converters.Audio
 \r
                     encoders.Remove(AudioEncoder.TrueHDPassthrough);\r
                 }\r
+                else if (task != null && task.OutputFormat == OutputFormat.WebM)\r
+                {\r
+                    encoders.RemoveAll(ae => !(ae.Equals(AudioEncoder.Vorbis) || ae.Equals(AudioEncoder.Opus)));\r
+                }\r
 \r
                 // Hide the Passthru options and show the "None" option\r
                 if (parameter != null && parameter.ToString() == "True")\r
index 12ce80eca05e712825fff44e1e0fb9f83c7f91e3..21db31b8a1ddab21e908454bc811f3d8d59b8f15 100644 (file)
@@ -79,12 +79,16 @@ namespace HandBrakeWPF.Converters.Video
                     encoders.Remove(VideoEncoder.X265_12);\r
                 }\r
 \r
-                if (task != null && task.OutputFormat != OutputFormat.Mkv)\r
+                if (task != null && task.OutputFormat == OutputFormat.Mp4)\r
                 {\r
                     encoders.Remove(VideoEncoder.Theora);\r
                     encoders.Remove(VideoEncoder.VP8);\r
                     encoders.Remove(VideoEncoder.VP9);\r
                 }\r
+                else if (task != null && task.OutputFormat == OutputFormat.WebM)\r
+                {\r
+                    encoders.RemoveAll(ve => !(ve.Equals(VideoEncoder.VP9) || ve.Equals(VideoEncoder.VP8)));\r
+                }\r
 \r
                 if (!isQsvEnabled || !SystemInfo.IsQsvAvailableH264)\r
                 {\r
index 0b000eff7a5f9af3add75dcd312a9ebdd188f0e9..fa6f71b96c4574d04e66da04a896c6677fbcde73 100644 (file)
@@ -172,6 +172,10 @@ namespace HandBrakeWPF.Helpers
                 {\r
                     destinationFilename += ".mkv";\r
                 }\r
+                else if (task.OutputFormat == OutputFormat.WebM)\r
+                {\r
+                    destinationFilename += ".webm";\r
+                }\r
 \r
                 /*\r
                  * File Destination Path\r
index b9c05191f32e280e56b9ca2b31a1ae7725795993..54f78fe922d520da3cf98bac07066f2816764480 100644 (file)
@@ -4616,6 +4616,28 @@ namespace HandBrakeWPF.Properties {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to WebM in HandBrake only supports burned subtitles.
+        ///
+        ///You should change your subtitle selections.
+        ///
+        ///If you continue, your non-burned subtitles will be lost..
+        /// </summary>
+        public static string Subtitles_WebmSubtitleIncompatibilityError {
+            get {
+                return ResourceManager.GetString("Subtitles_WebmSubtitleIncompatibilityError", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to WebM Subtitle Compatibility.
+        /// </summary>
+        public static string Subtitles_WebmSubtitleIncompatibilityHeader {
+            get {
+                return ResourceManager.GetString("Subtitles_WebmSubtitleIncompatibilityHeader", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Add Closed Captions when available.
         /// </summary>
index 1cf4cfc4e0c165b3f7535f8d0c8a4b32a6d51d5d..d6117ac7be09dae021928bfb308dcb4db8f65e20 100644 (file)
@@ -371,6 +371,16 @@ Please choose a different filename.</value>
 Foreign Audio Track - The Foreign Audio track will be burned in if available. \r
 First Track - The first track will be burned in.\r
 Foreign Audio Preferred, else First - If the foreign audio track exists, it will be burned in, otherwise the first track will be chosen.</value>\r
+  </data>\r
+  <data name="Subtitles_WebmSubtitleIncompatibilityHeader" xml:space="preserve">\r
+    <value>WebM Subtitle Compatibility</value>\r
+  </data>\r
+  <data name="Subtitles_WebmSubtitleIncompatibilityError" xml:space="preserve">\r
+    <value>WebM in HandBrake only supports burned subtitles.\r
+\r
+You should change your subtitle selections.\r
+\r
+If you continue, your non-burned subtitles will be lost.</value>\r
   </data>\r
   <data name="Main_ScanNoTitlesFound" xml:space="preserve">\r
     <value>No valid source or titles found.</value>\r
index dc4f004803529ef1e6162c8c11c54a6b3463a4c6..e9eb3c53a7e782ea0d5998e926c98b49714e6529 100644 (file)
@@ -23,5 +23,9 @@ namespace HandBrakeWPF.Services.Encode.Model.Models
         [DisplayName("MKV")]
         [ShortName("mkv")]
         Mkv,
+
+        [DisplayName("WebM")]
+        [ShortName("webm")]
+        WebM
     }
 }
index 90a3d249f1af2a299e3aa07603649bd5dff43f63..9af13bc7131a9081732ba62739d94d247121d571 100644 (file)
@@ -209,6 +209,14 @@ namespace HandBrakeWPF.ViewModels
                 }\r
             }\r
 \r
+            if (this.Task.OutputFormat == OutputFormat.WebM)\r
+            {\r
+                foreach (AudioTrack track in this.Task.AudioTracks.Where(track => track.Encoder != AudioEncoder.Vorbis && track.Encoder != AudioEncoder.Opus))\r
+                {\r
+                    track.Encoder = AudioEncoder.Vorbis;\r
+                }\r
+            }\r
+\r
             this.AudioDefaultsViewModel.RefreshTask();\r
         }\r
 \r
index c5f0f5e3c7f60557c591beba6849b8d686e0ed2b..4889332eebe800ae79cccb7da441572a30a31f9b 100644 (file)
@@ -28,5 +28,15 @@ namespace HandBrakeWPF.ViewModels.Interfaces
         /// String array of files.\r
         /// </param>\r
         void Import(string[] subtitleFiles);\r
+\r
+        /// <summary>\r
+        /// Trigger a Notify Property Changed on the Task to force various UI elements to update.\r
+        /// </summary>\r
+        void RefreshTask();\r
+\r
+        /// <summary>\r
+        /// Checks the configuration of the subtitles and warns the user about any potential issues.\r
+        /// </summary>\r
+        bool ValidateSubtitles();\r
     }\r
 }\r
index de7070d3d96283e639fb5ae865d9cd7a35174e05..2f0baa730a6785a4b5d29d9831bbd75c55a23915 100644 (file)
@@ -556,7 +556,7 @@ namespace HandBrakeWPF.ViewModels
         /// <summary>\r
         /// Gets RangeMode.\r
         /// </summary>\r
-        public IEnumerable<OutputFormat> OutputFormats => new List<OutputFormat> { OutputFormat.Mp4, OutputFormat.Mkv };\r
+        public IEnumerable<OutputFormat> OutputFormats => new List<OutputFormat> { OutputFormat.Mp4, OutputFormat.Mkv, OutputFormat.WebM };\r
 \r
         /// <summary>\r
         /// Gets or sets Destination.\r
@@ -608,6 +608,9 @@ namespace HandBrakeWPF.ViewModels
                             case ".m4v":\r
                                 this.SummaryViewModel.SetContainer(OutputFormat.Mp4);\r
                                 break;\r
+                            case ".webm":\r
+                                this.SummaryViewModel.SetContainer(OutputFormat.WebM);\r
+                                break;\r
                         }\r
                     }\r
                     else\r
@@ -1154,6 +1157,7 @@ namespace HandBrakeWPF.ViewModels
 \r
             this.VideoViewModel.RefreshTask();\r
             this.AudioViewModel.RefreshTask();\r
+            this.SubtitleViewModel.RefreshTask();\r
         }\r
 \r
         public void Shutdown()\r
@@ -1377,6 +1381,12 @@ namespace HandBrakeWPF.ViewModels
                 return new AddQueueError(Resources.Main_MatchingFileOverwriteWarning, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);\r
             }\r
 \r
+            // defer to subtitle's validation messages\r
+            if (!this.SubtitleViewModel.ValidateSubtitles())\r
+            {\r
+                return false;\r
+            }\r
+\r
             QueueTask task = new QueueTask(new EncodeTask(this.CurrentTask), HBConfigurationFactory.Create(), this.ScannedSource.ScanPath, this.SelectedPreset);\r
 \r
             if (!this.queueProcessor.CheckForDestinationPathDuplicates(task.Task.Destination))\r
@@ -1731,7 +1741,7 @@ namespace HandBrakeWPF.ViewModels
         {\r
             SaveFileDialog saveFileDialog = new SaveFileDialog\r
             {\r
-                Filter = "mp4|*.mp4;*.m4v|mkv|*.mkv", \r
+                Filter = "mp4|*.mp4;*.m4v|mkv|*.mkv|webm|*.webm", \r
                 CheckPathExists = true, \r
                 AddExtension = true, \r
                 DefaultExt = ".mp4", \r
@@ -1743,7 +1753,9 @@ namespace HandBrakeWPF.ViewModels
             saveFileDialog.FilterIndex = !string.IsNullOrEmpty(this.CurrentTask.Destination)\r
                                          && !string.IsNullOrEmpty(extension)\r
                                              ? (extension == ".mp4" || extension == ".m4v" ? 1 : 2)\r
-                                             : (this.CurrentTask.OutputFormat == OutputFormat.Mkv ? 2 : 0);\r
+                                             : (this.CurrentTask.OutputFormat == OutputFormat.Mkv \r
+                                                 ? 2 \r
+                                                 : (this.CurrentTask.OutputFormat == OutputFormat.WebM ? 3 : 0));\r
 \r
             string mruDir = this.GetMru(Constants.FileSaveMru);\r
             if (!string.IsNullOrEmpty(mruDir))\r
@@ -1781,6 +1793,9 @@ namespace HandBrakeWPF.ViewModels
                         case ".m4v":\r
                             this.SummaryViewModel.SetContainer(OutputFormat.Mp4);\r
                             break;\r
+                        case ".webm":\r
+                            this.SummaryViewModel.SetContainer(OutputFormat.WebM);\r
+                            break;\r
                     }\r
 \r
                     this.NotifyOfPropertyChange(() => this.CurrentTask);\r
index d8ad6e9b9f711bebd18657e0649340869bf13163..5a9c38383a6d6610a0658c6d18e46cb844db709e 100644 (file)
@@ -570,7 +570,21 @@ namespace HandBrakeWPF.ViewModels
             // Filename handling.\r
             if (string.IsNullOrEmpty(encodeTask.Destination))\r
             {\r
-                string filename = Path.ChangeExtension(Path.GetTempFileName(), encodeTask.OutputFormat == OutputFormat.Mkv ? "m4v" : "mkv");\r
+                string formatExtension;\r
+                switch (encodeTask.OutputFormat)\r
+                {\r
+                    case OutputFormat.WebM:\r
+                        formatExtension = "webm";\r
+                        break;\r
+                    case OutputFormat.Mp4:\r
+                        formatExtension = "m4v";\r
+                        break;\r
+                    case OutputFormat.Mkv:\r
+                    default:\r
+                        formatExtension = "mkv";\r
+                        break;\r
+                }\r
+                string filename = Path.ChangeExtension(Path.GetTempFileName(), formatExtension);\r
                 encodeTask.Destination = filename;\r
                 this.CurrentlyPlaying = filename;\r
             }\r
index e164f11922de5ccf880396650df9f4bcd50afc0a..432e15f516ff2842408bd2a4f40ab45d80811d0b 100644 (file)
@@ -14,6 +14,7 @@ namespace HandBrakeWPF.ViewModels
     using System.IO;\r
     using System.Linq;\r
     using System.Runtime.CompilerServices;\r
+    using System.Windows;\r
 \r
     using Caliburn.Micro;\r
 \r
@@ -22,6 +23,7 @@ namespace HandBrakeWPF.ViewModels
     using HandBrakeWPF.EventArgs;\r
     using HandBrakeWPF.Model.Subtitles;\r
     using HandBrakeWPF.Properties;\r
+    using HandBrakeWPF.Services.Interfaces;\r
     using HandBrakeWPF.Services.Presets.Model;\r
     using HandBrakeWPF.Services.Scan.Model;\r
     using HandBrakeWPF.ViewModels.Interfaces;\r
@@ -38,6 +40,7 @@ namespace HandBrakeWPF.ViewModels
     /// </summary>\r
     public class SubtitlesViewModel : ViewModelBase, ISubtitlesViewModel\r
     {\r
+        private readonly IErrorService errorService;\r
         private readonly IWindowManager windowManager;\r
 \r
         #region Constants and Fields\r
@@ -52,11 +55,15 @@ namespace HandBrakeWPF.ViewModels
         /// <summary>\r
         /// Initializes a new instance of the <see cref="HandBrakeWPF.ViewModels.SubtitlesViewModel"/> class.\r
         /// </summary>\r
+        /// <param name="errorService">\r
+        /// The Error Service\r
+        /// </param>\r
         /// <param name="windowManager">\r
         /// The window Manager.\r
         /// </param>\r
-        public SubtitlesViewModel(IWindowManager windowManager)\r
+        public SubtitlesViewModel(IErrorService errorService, IWindowManager windowManager)\r
         {\r
+            this.errorService = errorService;\r
             this.windowManager = windowManager;\r
             this.SubtitleDefaultsViewModel = new SubtitlesDefaultsViewModel();\r
             this.Task = new EncodeTask();\r
@@ -144,6 +151,14 @@ namespace HandBrakeWPF.ViewModels
             }\r
         }\r
 \r
+        public bool IsBurnableOnly\r
+        {\r
+            get\r
+            {\r
+                return this.Task.OutputFormat == OutputFormat.WebM;\r
+            }\r
+        }\r
+\r
         #endregion\r
 \r
         #region Public Methods\r
@@ -453,6 +468,26 @@ namespace HandBrakeWPF.ViewModels
             this.AutomaticSubtitleSelection();\r
         }\r
 \r
+        /// <summary>\r
+        /// Trigger a Notify Property Changed on the Task to force various UI elements to update.\r
+        /// </summary>\r
+        public void RefreshTask()\r
+        {\r
+            this.NotifyOfPropertyChange(() => this.Task);\r
+            this.NotifyOfPropertyChange(() => this.IsBurnableOnly);\r
+\r
+            if (this.IsBurnableOnly)\r
+            {\r
+                foreach (var subtitleTrack in this.Task.SubtitleTracks)\r
+                {\r
+                    if (subtitleTrack.Default)\r
+                    {\r
+                        subtitleTrack.Default = false;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
         #endregion\r
 \r
         #region Implemented Interfaces\r
@@ -553,6 +588,43 @@ namespace HandBrakeWPF.ViewModels
             this.AutomaticSubtitleSelection();\r
         }\r
 \r
+        /// <summary>\r
+        /// Checks the configuration of the subtitles and warns the user about any potential issues.\r
+        /// </summary>\r
+        public bool ValidateSubtitles()\r
+        {\r
+            var nonBurnedSubtitles = this.Task.SubtitleTracks.Where(subtitleTrack => !subtitleTrack.Burned).ToList();\r
+\r
+            if (nonBurnedSubtitles.Count > 0 && this.IsBurnableOnly)\r
+            {\r
+                MessageBoxResult result = this.errorService.ShowMessageBox(\r
+                    Resources.Subtitles_WebmSubtitleIncompatibilityError,\r
+                    Resources.Subtitles_WebmSubtitleIncompatibilityHeader,\r
+                    MessageBoxButton.OKCancel,\r
+                    MessageBoxImage.Warning);\r
+                if (result == MessageBoxResult.OK)\r
+                {\r
+                    foreach (var subtitleTrack in nonBurnedSubtitles)\r
+                    {\r
+                        if (!subtitleTrack.Burned)\r
+                        {\r
+                            this.Remove(subtitleTrack);\r
+                        }\r
+                    }\r
+                }\r
+                else if (result == MessageBoxResult.Cancel)\r
+                {\r
+                    return false;\r
+                }\r
+                else\r
+                {\r
+                    return false;\r
+                }\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
         #endregion\r
 \r
         #region Methods\r
index 0da1fc70b85df2923f403ac9d5dfc426905fecba..b5f711e5a813efa1e9cc2ffeb225768793ee7a3d 100644 (file)
@@ -123,7 +123,7 @@ namespace HandBrakeWPF.ViewModels
             {
                 return new List<OutputFormat>
                        {
-                           OutputFormat.Mp4, OutputFormat.Mkv
+                           OutputFormat.Mp4, OutputFormat.Mkv, OutputFormat.WebM
                        };
             }
         }
@@ -211,8 +211,9 @@ namespace HandBrakeWPF.ViewModels
                     this.Task.OutputFormat = value;
                     this.NotifyOfPropertyChange(() => this.SelectedOutputFormat);
                     this.NotifyOfPropertyChange(() => this.Task.OutputFormat);
-                    this.NotifyOfPropertyChange(() => this.IsMkv);
+                    this.NotifyOfPropertyChange(() => this.IsMkvOrWebm);
                     this.SetExtension(string.Format(".{0}", this.Task.OutputFormat.ToString().ToLower()));
+                    this.UpdateDisplayedInfo(); // output format may coreced to another due to container incompatibility
 
                     this.OnOutputFormatChanged(new OutputFormatChangedEventArgs(null));
                     this.OnTabStatusChanged(null);
@@ -221,13 +222,13 @@ namespace HandBrakeWPF.ViewModels
         }
 
         /// <summary>
-        /// Gets or sets a value indicating whether IsMkv.
+        /// Gets or sets a value indicating whether IsMkvOrWebm.
         /// </summary>
-        public bool IsMkv
+        public bool IsMkvOrWebm
         {
             get
             {
-                return this.SelectedOutputFormat == OutputFormat.Mkv;
+                return this.SelectedOutputFormat == OutputFormat.Mkv || this.SelectedOutputFormat == OutputFormat.WebM;
             }
         }
 
@@ -316,8 +317,8 @@ namespace HandBrakeWPF.ViewModels
             this.UpdateDisplayedInfo();
 
             this.NotifyOfPropertyChange(() => this.SelectedOutputFormat);
-            this.NotifyOfPropertyChange(() => this.IsMkv);
-
+            this.NotifyOfPropertyChange(() => this.IsMkvOrWebm);
             this.NotifyOfPropertyChange(() => this.OptimizeMP4);
             this.NotifyOfPropertyChange(() => this.IPod5GSupport);
             this.NotifyOfPropertyChange(() => this.AlignAVStart);
@@ -454,14 +455,14 @@ namespace HandBrakeWPF.ViewModels
             }
 
             // Now disable controls that are not required. The Following are for MP4 only!
-            if (newExtension == ".mkv")
+            if (newExtension == ".mkv" || newExtension == ".webm")
             {
                 this.OptimizeMP4 = false;
                 this.IPod5GSupport = false;
                 this.AlignAVStart = false;
             }
 
-            this.NotifyOfPropertyChange(() => this.IsMkv);
+            this.NotifyOfPropertyChange(() => this.IsMkvOrWebm);
 
             // Update The browse file extension display
             if (Path.HasExtension(newExtension))
index 72b74ffa1f7c66c3d7c9d3e24820266063617442..3280b94242a970d2828496666600bd4fa0cb62d8 100644 (file)
@@ -1115,10 +1115,17 @@ namespace HandBrakeWPF.ViewModels
         {\r
             this.NotifyOfPropertyChange(() => this.Task);\r
 \r
-            if ((Task.OutputFormat == OutputFormat.Mp4) && this.SelectedVideoEncoder == VideoEncoder.Theora)\r
+            VideoEncoder[] allowableWebmEncoders = { VideoEncoder.VP8, VideoEncoder.VP9 };\r
+\r
+            if ((Task.OutputFormat == OutputFormat.Mp4) && (this.SelectedVideoEncoder == VideoEncoder.Theora || allowableWebmEncoders.Contains(this.SelectedVideoEncoder)))\r
             {\r
                 this.SelectedVideoEncoder = VideoEncoder.X264;\r
             }\r
+\r
+            if ((Task.OutputFormat == OutputFormat.WebM) && !allowableWebmEncoders.Contains(this.SelectedVideoEncoder))\r
+            {\r
+                this.SelectedVideoEncoder = VideoEncoder.VP8;\r
+            }\r
         }\r
 \r
         /// <summary>\r
index 01195259a679d733be7c9aba008ac99ede16be44..1fedb3962ccfa73285d31d03bb366918d7ee58d9 100644 (file)
              xmlns:splitButton="clr-namespace:HandBrakeWPF.Controls.SplitButton"\r
              xmlns:Properties="clr-namespace:HandBrakeWPF.Properties"\r
              xmlns:subtitles="clr-namespace:HandBrakeWPF.Converters.Subtitles"\r
+             xmlns:viewModels="clr-namespace:HandBrakeWPF.ViewModels"\r
              d:DesignHeight="350"\r
              d:DesignWidth="500"\r
              mc:Ignorable="d"\r
              x:Name="subTab">\r
     <UserControl.Resources>\r
         <Converters:BooleanToVisibilityConverter x:Key="booleanToVisConverter" />\r
+        <Converters:BooleanConverter x:Key="booleanConverter" />\r
         <subtitles:CanBurnSubtitleConverter x:Key="canBurnSubtitleConverter" />\r
 \r
         <Style x:Key="LongToolTip" TargetType="TextBlock">\r
                                 </i:Interaction.Triggers>\r
                             </CheckBox>\r
 \r
-                            <CheckBox Grid.Column="5" Margin="5,0,5,0" VerticalAlignment="Center" IsChecked="{Binding Default}" Content="{x:Static Properties:Resources.SubtitlesView_Default}" FontWeight="Bold">\r
+                            <CheckBox Grid.Column="5" Margin="5,0,5,0" VerticalAlignment="Center" IsChecked="{Binding Default}" Content="{x:Static Properties:Resources.SubtitlesView_Default}" FontWeight="Bold"\r
+                                      IsEnabled="{Binding DataContext.IsBurnableOnly, Converter={StaticResource booleanConverter}, ConverterParameter=true, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">\r
                                 <i:Interaction.Triggers>\r
                                     <i:EventTrigger EventName="Click">\r
                                         <cal:ActionMessage MethodName="SelectDefaultTrack">\r
                                 </i:Interaction.Triggers>\r
                             </CheckBox>\r
 \r
-                            <CheckBox Grid.Column="9" Margin="5,0,5,0" VerticalAlignment="Center" IsChecked="{Binding Default}" Content="Default" FontWeight="Bold">\r
+                            <CheckBox Grid.Column="9" Margin="5,0,5,0" VerticalAlignment="Center" IsChecked="{Binding Default}" Content="Default" FontWeight="Bold"\r
+                                      IsEnabled="{Binding DataContext.IsBurnableOnly, Converter={StaticResource booleanConverter}, ConverterParameter=true, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">\r
                                 <i:Interaction.Triggers>\r
                                     <i:EventTrigger EventName="Click">\r
                                         <cal:ActionMessage MethodName="SelectDefaultTrack">\r
index 10027f60ec8e6ed86176ffc5605e18ea0c51bb47..8aad4a3a25b37756c3ef9705b1c032c1547a28bd 100644 (file)
                               Content="{x:Static Properties:Resources.MainView_WebOptimized}"
                               IsChecked="{Binding Path=OptimizeMP4}"
                               ToolTip="{x:Static Properties:ResourcesTooltips.MainView_Optimise}"
-                              Visibility="{Binding IsMkv, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}" />
+                              Visibility="{Binding IsMkvOrWebm, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}" />
             <CheckBox Name="AlignAVStart" VerticalAlignment="Center" Grid.Row="2" Grid.Column="1"
                               Content="{x:Static Properties:Resources.MainView_AlignAVStart}"
                               ToolTip="{x:Static Properties:ResourcesTooltips.MainView_AlignAVStart}"
                               IsChecked="{Binding Path=AlignAVStart}"
-                              Visibility="{Binding IsMkv, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}" />
+                              Visibility="{Binding IsMkvOrWebm, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}" />
             <CheckBox Name="iPod5G" VerticalAlignment="Center" Grid.Row="3" Grid.Column="1"
                               Content="{x:Static Properties:Resources.MainView_iPod5G}"
                               ToolTip="{x:Static Properties:ResourcesTooltips.MainView_IpodAtom}"
                               IsChecked="{Binding Path=IPod5GSupport}"
-                              Visibility="{Binding IsMkv, Converter={StaticResource boolToVisConverter},  ConverterParameter=true}" />
+                              Visibility="{Binding IsMkvOrWebm, Converter={StaticResource boolToVisConverter},  ConverterParameter=true}" />
 
             <TextBlock Text="Tracks:" FontWeight="Bold" Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" />
             <TextBlock Text="{Binding VideoTrackInfo}" Grid.Row="5" Grid.Column="1" VerticalAlignment="Center" />