rtMedia for WordPress, BuddyPress and bbPress - Version 4.5.7

Version Description

rtMedia 4.5.7, with fixes for, media duplication in the lightbox, multiple media upload for non-admin roles, some UI fixes along with introduced new filters.

=

Download this release

Release Info

Developer thrijith
Plugin Icon 128x128 rtMedia for WordPress, BuddyPress and bbPress
Version 4.5.7
Comparing to
See all releases

Code changes from version 4.5.6 to 4.5.7

Files changed (78) hide show
  1. app/admin/RTMediaAdmin.php +1 -1
  2. app/admin/RTMediaFormHandler.php +2 -2
  3. app/assets/admin/js/admin.min.js +1 -1
  4. app/assets/admin/js/settings.js +1 -0
  5. app/assets/css/rtmedia.css +19 -7
  6. app/assets/css/rtmedia.min.css +1 -1
  7. app/assets/css/sass/_media-tab.scss +4 -0
  8. app/assets/css/sass/_popup.scss +9 -10
  9. app/assets/css/sass/_rtm.scss +13 -3
  10. app/assets/js/rtMedia.backbone.js +28 -20
  11. app/assets/js/rtMedia.js +47 -0
  12. app/assets/js/rtmedia.min.js +2 -2
  13. app/helper/RTMediaSupport.php +3 -3
  14. app/main/controllers/activity/RTMediaActivity.php +127 -47
  15. app/main/controllers/activity/RTMediaBuddyPressActivity.php +11 -0
  16. app/main/controllers/media/RTMediaAlbum.php +1 -1
  17. app/main/controllers/media/RTMediaFeatured.php +1 -1
  18. app/main/controllers/media/RTMediaGalleryItemAction.php +3 -3
  19. app/main/controllers/media/RTMediaGroupFeatured.php +1 -1
  20. app/main/controllers/media/RTMediaLoginPopup.php +1 -1
  21. app/main/controllers/media/RTMediaMedia.php +2 -2
  22. app/main/controllers/media/RTMediaTags.php +11 -5
  23. app/main/controllers/media/RTMediaUserInteraction.php +2 -1
  24. app/main/controllers/template/rtmedia-actions.php +6 -6
  25. app/main/controllers/template/rtmedia-filters.php +5 -18
  26. app/main/controllers/template/rtmedia-functions.php +14 -8
  27. app/main/controllers/upload/RTMediaUploadView.php +4 -4
  28. index.php +2 -2
  29. languages/buddypress-media.po +3 -3
  30. lib/getid3/extension.cache.dbm.php +54 -12
  31. lib/getid3/extension.cache.mysql.php +50 -14
  32. lib/getid3/extension.cache.mysqli.php +220 -0
  33. lib/getid3/extension.cache.sqlite3.php +121 -84
  34. lib/getid3/getid3.lib.php +562 -121
  35. lib/getid3/getid3.php +1835 -1499
  36. lib/getid3/module.archive.gzip.php +40 -16
  37. lib/getid3/module.archive.rar.php +14 -9
  38. lib/getid3/module.archive.szip.php +11 -9
  39. lib/getid3/module.archive.tar.php +22 -8
  40. lib/getid3/module.archive.xz.php +42 -0
  41. lib/getid3/module.archive.zip.php +70 -36
  42. lib/getid3/module.audio-video.asf.php +106 -35
  43. lib/getid3/module.audio-video.bink.php +16 -9
  44. lib/getid3/module.audio-video.flv.php +187 -26
  45. lib/getid3/module.audio-video.matroska.php +132 -23
  46. lib/getid3/module.audio-video.mpeg.php +100 -27
  47. lib/getid3/module.audio-video.nsv.php +35 -18
  48. lib/getid3/module.audio-video.quicktime.php +1844 -1217
  49. lib/getid3/module.audio-video.real.php +24 -11
  50. lib/getid3/module.audio-video.riff.php +181 -48
  51. lib/getid3/module.audio-video.swf.php +10 -7
  52. lib/getid3/module.audio-video.ts.php +16 -10
  53. lib/getid3/module.audio.aa.php +13 -11
  54. lib/getid3/module.audio.aac.php +45 -20
  55. lib/getid3/module.audio.ac3.php +520 -176
  56. lib/getid3/module.audio.amr.php +19 -9
  57. lib/getid3/module.audio.au.php +25 -8
  58. lib/getid3/module.audio.avr.php +10 -8
  59. lib/getid3/module.audio.bonk.php +20 -8
  60. lib/getid3/module.audio.dsf.php +139 -0
  61. lib/getid3/module.audio.dss.php +42 -24
  62. lib/getid3/module.audio.dts.php +63 -20
  63. lib/getid3/module.audio.flac.php +85 -22
  64. lib/getid3/module.audio.la.php +18 -16
  65. lib/getid3/module.audio.lpac.php +16 -13
  66. lib/getid3/module.audio.midi.php +35 -17
  67. lib/getid3/module.audio.mod.php +29 -16
  68. lib/getid3/module.audio.monkey.php +24 -11
  69. lib/getid3/module.audio.mp3.php +200 -72
  70. lib/getid3/module.audio.mpc.php +57 -17
  71. lib/getid3/module.audio.ogg.php +120 -42
  72. lib/getid3/module.audio.optimfrog.php +54 -15
  73. lib/getid3/module.audio.rkau.php +16 -10
  74. lib/getid3/module.audio.shorten.php +16 -14
  75. lib/getid3/module.audio.tta.php +10 -8
  76. lib/getid3/module.audio.voc.php +25 -8
  77. lib/getid3/module.audio.vqf.php +24 -11
  78. lib/getid3/module.audio.wavpack.php +10 -8
app/admin/RTMediaAdmin.php CHANGED
@@ -1840,7 +1840,7 @@ if ( ! class_exists( 'RTMediaAdmin' ) ) {
1840
  // tab icon
1841
  $icon = '';
1842
  if ( isset( $tab['icon'] ) && ! empty( $tab['icon'] ) ) {
1843
- $icon = '<i class="' . esc_attr( $tab['icon'] ) . ' dashicons rtmicon"></i>';
1844
  }
1845
  ?>
1846
  <li class="<?php echo esc_attr( $active_class ) ?> <?php echo esc_attr( $error_class ) ?>">
1840
  // tab icon
1841
  $icon = '';
1842
  if ( isset( $tab['icon'] ) && ! empty( $tab['icon'] ) ) {
1843
+ $icon = '<i class="' . esc_attr( $tab['icon'] ) . ' dashicons"></i>';
1844
  }
1845
  ?>
1846
  <li class="<?php echo esc_attr( $active_class ) ?> <?php echo esc_attr( $error_class ) ?>">
app/admin/RTMediaFormHandler.php CHANGED
@@ -881,7 +881,7 @@ class RTMediaFormHandler {
881
  if ( 'other' !== $key ) {
882
  ?>
883
  <span class="rtm-tooltip rtm-extensions">
884
- <i class="dashicons dashicons-info rtmicon"></i>
885
  <span class="rtm-tip">
886
  <strong><?php echo esc_html__( 'File Extensions', 'buddypress-media' ); ?></strong><br/>
887
  <hr/>
@@ -1568,7 +1568,7 @@ class RTMediaFormHandler {
1568
  <span
1569
  class="rtm-field-wrap"><?php call_user_func( $option['callback'], $option['args'] ); ?></span>
1570
  <span class="rtm-tooltip">
1571
- <i class="dashicons dashicons-info rtmicon"></i>
1572
  <span class="rtm-tip">
1573
  <?php echo wp_kses( ( isset( $option['args']['desc'] ) ) ? $option['args']['desc'] : 'NA', array(
1574
  'a' => array(
881
  if ( 'other' !== $key ) {
882
  ?>
883
  <span class="rtm-tooltip rtm-extensions">
884
+ <i class="dashicons dashicons-info"></i>
885
  <span class="rtm-tip">
886
  <strong><?php echo esc_html__( 'File Extensions', 'buddypress-media' ); ?></strong><br/>
887
  <hr/>
1568
  <span
1569
  class="rtm-field-wrap"><?php call_user_func( $option['callback'], $option['args'] ); ?></span>
1570
  <span class="rtm-tooltip">
1571
+ <i class="dashicons dashicons-info"></i>
1572
  <span class="rtm-tip">
1573
  <?php echo wp_kses( ( isset( $option['args']['desc'] ) ) ? $option['args']['desc'] : 'NA', array(
1574
  'a' => array(
app/assets/admin/js/admin.min.js CHANGED
@@ -3,4 +3,4 @@
3
  * @package rtMedia
4
  */
5
 
6
- function rtmedia_addon_do_not_show(){var a={action:"rtmedia_addon_popup_not_show_again"};jQuery.post(rtmedia_admin_ajax,a,function(a){jQuery("#TB_window").remove(),jQuery("#TB_overlay").remove()})}"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b}),function(a,b,c,d){var e={init:function(b,c){var d=this;d.elem=c,d.$elem=a(c),d.options=a.extend({},a.fn.rtTab.options,b),d.rtTabs()},rtTabs:function(){var c=this,d=c.options.activeTab;if(c.$elem.find("li:nth-child("+d+")").addClass("active"),c.rtTabContent(activeTabContent="yes"),c.rtClick(),!0==("false"!==c.$elem.attr("data-hash"))){var e=b.location.hash;e&&c.$elem.find("li").find('a[href="'+e+'"]').trigger("click"),a(b).on("hashchange",function(){var a=b.location.hash;c.$elem.find("li").find('a[href="'+a+'"]').trigger("click")})}},rtClick:function(){var c=this,d=c.$elem.find("li");d.find("a").on("click",function(e){e.preventDefault(),d.removeClass("active"),c.rtTabContent(),a(this).parent().addClass("active");var f=a(this).attr("href");if(a(f).removeClass("hide"),1==("false"!==c.$elem.attr("data-hash"))){var g=a(b).scrollTop();location.hash=a(this).attr("href"),a(b).scrollTop(g)}"function"==typeof c.options.onComplete&&c.options.onComplete.apply(c.elem,arguments)})},rtTabContent:function(b){this.$elem.find("li").find("a").each(function(){var c=a(this),d=c.attr("href");"yes"===b?c.parent().hasClass("active")||a(d).addClass("hide"):a(d).addClass("hide")})}};a.fn.rtTab=function(b){return this.each(function(){var c=Object.create(e);c.init(b,this),a.data(this,"rtTab",c)})},a.fn.rtTab.options={activeTab:1,onComplete:null}}(jQuery,window,document),jQuery(document).ready(function(a){var b=document.createElement("div");b.setAttribute("class","rtm-warning rtm-fly-warning hide"),a(".rtm-tabs").rtTab(),a('input[name^="rtmedia-options"]').on("change",function(){a(".rtm-save-settings-msg").remove(),0===a(".rtm-fly-warning").length&&(b.innerText=rtmedia_admin_strings.settings_changed,a(".rtm-button-container.top").prepend(b),a(".rtm-fly-warning").slideDown())}),a(".rtm-img-size-setting .form-table tr:nth-child(7) td:last-child").attr("colspan","3"),a(".rtm-field-wrap .switch input[type=checkbox]").each(function(){var b=a(this);b.parents("table").attr("data-depends")||(b.is(":checked")?(b.parents("table").next(".rtm-notice").slideDown(),b.parents("table").siblings("table").each(function(){a(this).attr("data-depends")&&a(this).slideDown()})):(b.parents("table").next(".rtm-notice").slideUp(),b.parents("table").siblings("table").each(function(){a(this).attr("data-depends")&&a(this).slideUp()}))),b.parents("tr").next("tr").attr("data-depends")&&(b.is(":checked")?b.parents("tr").next("tr").slideDown():b.parents("tr").next("tr").slideUp())}),a(".rtm-field-wrap .switch input[type=checkbox]").on("change",function(){var b=a(this);b.parents("table").attr("data-depends")||(b.parents("table").next(".rtm-notice").slideToggle(),b.parents("table").siblings("table").each(function(){a(this).attr("data-depends")&&a(this).slideToggle()})),b.parents("tr").next("tr").attr("data-depends")&&b.parents("tr").next("tr").slideToggle()});var c=Backbone.View.extend({el:a(".bp-media-admin"),events:{"click .rtm-theme":"render","click .rtm-close":"close","click .rtm-previous":"previousTheme","click .rtm-next":"nextTheme",keyup:"keyEvent"},initialize:function(){_.bindAll(this,"render","close","nextTheme","previousTheme","keyEvent"),this.keyEvent()},render:function(b){a(".rtm-theme").removeClass("rtm-modal-open");var c=a(b.currentTarget).addClass("rtm-modal-open").find(".rtm-theme-content").html();if(a(".rtm-theme-overlay")[0])a(".rtm-theme-overlay").show(),a(this.el).find(".rtm-theme-content-wrap").empty().append(c);else{var d={themeContent:c};a(this.el).append(rtMediaAdmin.templates.rtm_theme_overlay(d))}a(b.currentTarget).is(":first-child")?a(".rtm-previous").addClass("disabled"):a(b.currentTarget).is(":last-child")?a(".rtm-next").addClass("disabled"):a(".rtm-next, .rtm-previous").removeClass("disabled")},close:function(){a(".rtm-theme").removeClass("rtm-modal-open"),a(".rtm-theme-overlay").hide(),a(".rtm-next, .rtm-previous").removeClass("disabled")},nextTheme:function(b){return a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:last-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").next().trigger("click"),!1},previousTheme:function(b){return a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:first-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").prev().trigger("click"),!1},keyEvent:function(){a("body").on("keyup",function(b){return 39===b.keyCode?(a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:last-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").next().trigger("click"),!1):37===b.keyCode?(a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:first-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").prev().trigger("click"),!1):void(27===b.keyCode&&a(".rtm-close").trigger("click"))})}});new c;jQuery("#rtm-licenses .regular-text").each(function(){jQuery(this).keypress(function(a){if("13"==(a.keyCode?a.keyCode:a.which))return!1})}),jQuery("#bp_media_settings_form").on("submit",function(a){jQuery("#rtcss-notice").remove();var b=jQuery("#rtmedia-custom-css").val(),c=b.match(/@import\s*(url)?\s*\(?([^;]+?)\)?;/);if(null!=c){if(null!=c[0])return jQuery("#rtmedia-custom-css").after('<div id="rtcss-notice" class="error"><p>'+rtmedia_admin_strings.wrong_css_input+"</p></div>"),!1}})});var rtMediaAdmin=new Object;rtMediaAdmin.templates={rtm_image:wp.template("rtm-image"),rtm_msg_div:wp.template("rtm-msg-div"),rtm_album_favourites_importer:wp.template("rtm-album-favourites-importer"),rtm_map_mapping_failure:wp.template("rtm-map-mapping-failure"),rtm_p_tag:wp.template("rtm-p-tag"),rtm_theme_overlay:wp.template("rtm-theme-overlay")},jQuery(document).ready(function(a){function b(a){return jQuery.post(ajaxurl,a,function(b){if(0!=b){var c=!1,d=Math.ceil((20*parseInt(b)+parseInt(a.values.finished))/parseInt(a.values.total)*100);d>100&&(d=100,c=!0),jQuery("#rtprogressbar>div").css("width",d+"%"),finished=jQuery("#rtprivacyinstaller span.finished").html(),jQuery("#rtprivacyinstaller span.finished").html(parseInt(finished)+a.count),c&&jQuery.post(ajaxurl,{action:"rtmedia_privacy_redirect"},function(a){window.location=settings_url})}else{var e={msg:"Row "+b+" failed."};jQuery("#map_progress_msgs").html(rtMediaAdmin.templates.rtm_map_mapping_failure(e))}})}function c(a){return jQuery.getJSON(ajaxurl,a,function(b){if(favorites=!1,b){var c=Math.ceil((5*parseInt(b.page)+parseInt(a.values.finished))/parseInt(a.values.total)*100);comments_total=jQuery("#bpmedia-bpalbumimporter .bp-album-comments span.total").html(),users_total=jQuery("#bpmedia-bpalbumimporter .bp-album-users span.total").html(),media_total=jQuery("#bpmedia-bpalbumimporter .bp-album-media span.total").html(),comments_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-comments span.finished").html(),users_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-users span.finished").html();var f=Math.ceil((parseInt(b.comments)+parseInt(comments_finished))/parseInt(comments_total)*100),g=Math.ceil(parseInt(b.users)/parseInt(users_total)*100);(c>100||100==c)&&(c=100,favorites=!0),jQuery(".bp-album-media #rtprogressbar>div").css("width",c+"%"),jQuery(".bp-album-comments #rtprogressbar>div").css("width",f+"%"),jQuery(".bp-album-users #rtprogressbar>div").css("width",g+"%"),media_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-media span.finished").html(),parseInt(media_finished)<parseInt(media_total)&&jQuery("#bpmedia-bpalbumimporter .bp-album-media span.finished").html(parseInt(media_finished)+a.count),jQuery("#bpmedia-bpalbumimporter .bp-album-comments span.finished").html(parseInt(b.comments)+parseInt(comments_finished)),jQuery("#bpmedia-bpalbumimporter .bp-album-users span.finished").html(parseInt(b.users)),favorites&&(favorite_data={action:"rtmedia_rt_album_import_favorites",rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},jQuery.post(ajaxurl,favorite_data,function(a){if(!a.hasOwnProperty(favorites)||0===a.favorites&&"0"===a.favorites)window.setTimeout(e,2e3);else{if(!jQuery(".bp-album-favorites").length){var b={users:a.users};jQuery(".bp-album-comments").after(rtMediaAdmin.templates.rtm_album_favourites_importer(b))}$favorites={},0!=a.offset||"0"!=a.offset?start=1*a.offset+1:start=1;for(var c=start;c<=a.users;c++)$count=1,c==a.users&&($count=parseInt(a.users%$count),0==$count&&($count=1)),newvals={action:"rtmedia_rt_album_import_step_favorites",offset:1*(c-1),redirect:c==a.users,rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},$favorites[c]=newvals;var f=jQuery.Deferred();f.resolve(),jQuery.each($favorites,function(a,b){f=f.pipe(function(){return d(b)})})}},"json"))}else if(a.hasOwnProperty(page)){var h={msg:"Row "+b.page+" failed."};jQuery("#map_progress_msgs").html(rtMediaAdmin.templates.rtm_map_mapping_failure(h))}else{var h={msg:rtmedia_admin_strings.request_failed};jQuery("#map_progress_msgs").html(rtMediaAdmin.templates.rtm_map_mapping_failure(h))}})}function d(a){return jQuery.post(ajaxurl,a,function(a){redirect=!1,favorites_total=jQuery("#bpmedia-bpalbumimporter .bp-album-favorites span.total").html(),favorites_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-favorites span.finished").html(),jQuery("#bpmedia-bpalbumimporter .bp-album-favorites span.finished").html(parseInt(favorites_finished)+1);var b=Math.ceil(parseInt(favorites_finished+1)/parseInt(favorites_total)*100);(b>100||100==b)&&(b=100,redirect=!0),jQuery(".bp-album-favorites #rtprogressbar>div").css("width",b+"%"),redirect&&window.setTimeout(e,2e3)})}function e(){window.location=document.URL}function f(a){j=a.target.files,g(a)}function g(a){a.stopPropagation(),a.preventDefault();var b=new FormData;void 0!==a&&void 0!==a.target&&void 0!==a.target.name&&"rtFileInput"===a.target.name&&b.append("import_export_control",a.target.name),jQuery.each(j,function(a,c){b.append(a,c)});var c=jQuery("#rtmedia_admin_upload_nonce").val();void 0!==c&&""!==c&&b.append("rtmedia_admin_upload_nonce",c),b.append("action","rtmedia_admin_upload"),jQuery.ajax({url:rtmedia_admin_ajax,type:"POST",data:b,cache:!1,processData:!1,contentType:!1,success:function(a){if(a.hasOwnProperty("rtm_response")&&a.hasOwnProperty("rtm_response_msg")){jQuery("#rtm-setting-msg").remove();var b=jQuery("<div/>",{id:"rtm-setting-msg",class:"rtm-fly-warning"});"success"===a.rtm_response?(b.addClass("rtm-success rtm-save-settings-msg"),b.text(a.rtm_response_msg),jQuery(".rtm-button-container.top").append(b),location.reload()):"error"===a.rtm_response&&(b.addClass("rtm-warning"),b.text(a.rtm_response_msg),jQuery(".rtm-button-container.top").append(b),b.delay(3e3).fadeOut(100))}if(void 0===a.error){if(a.exceed_size_msg)return jQuery("#debuglog").val(""),alert(a.exceed_size_msg),!1;jQuery("#debuglog_temp_path").val(a.debug_attachmanet)}else jQuery("#debuglog").val(""),alert("ERRORS: "+a.error)}})}var h=a("#rtm-licenses");h.length>0&&h.find(".license-inner:first input:first").focus();var i=document.createElement("div");i.className="support_form_loader",a(".rtm-save-settings-msg").length>0&&setTimeout(function(){a(".rtm-save-settings-msg").remove()},1e4),jQuery("#spread-the-word").on("click","#bp-media-add-linkback",function(){var a={action:"rtmedia_linkback",linkback:jQuery("#bp-media-add-linkback:checked").length};jQuery.post(rtmedia_admin_ajax,a,function(a){})}),jQuery("#bp-media-settings-boxes").on("change","#select-request",function(){if(jQuery(this).val()){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(i);var a={action:"rtmedia_select_request",form:jQuery(this).val()};jQuery.post(ajaxurl,a,function(a){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(a).fadeIn("slow")})}}),jQuery("#bp-media-settings-boxes").on("click","#cancel-request",function(){if(jQuery(this).val()){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(i);var a={action:"rtmedia_cancel_request"};jQuery.post(ajaxurl,a,function(a){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(a).fadeIn("slow")})}}),jQuery("#bp-media-settings-boxes").on("submit","#bp_media_settings_form, .rtmedia-settings-submit",function(a){var b=!0,c=new RegExp("^[0-9]+$");jQuery("input[name*='defaultSizes']").each(function(a){if(!c.test(jQuery(this).val()))return alert("Invalid value for "+jQuery(this).attr("name").replace("rtmedia-options[defaultSizes_","").replace("]","").replace(/_/g," ").replace(/(\b)([a-zA-Z] )/g,function(a){return a.toUpperCase()})),b=!1,!1});var d=jQuery('input[name^="rtmedia-options[general_videothumbs]"]');if(b&&d.length>0&&void 0!==d){var e="",f=0;if(d.val()<=0?(e+=rtmedia_admin_strings.video_thumbnail_error,f=2):c.test(d.val())||(e+=rtmedia_admin_strings.video_thumbnail_invalid_value+" "+Math.round(d.val())+".",f=Math.round(d.val())),""!=e)return alert(e),d.val(f),b=!1,!1}var g=jQuery('input[name^="rtmedia-options[general_jpeg_image_quality]"]');if(b&&g.length>0&&void 0!==g){var e="",h=0;if(g.val()<=0?(e+=rtmedia_admin_strings.jpeg_quality_negative_error,h=90):g.val()>100?(e+=rtmedia_admin_strings.jpeg_quality_percentage_error,h=100):c.test(g.val())||(e+=rtmedia_admin_strings.jpeg_quality_invalid_value+" "+Math.round(g.val())+".",h=Math.round(g.val())),""!=e)return alert(e),g.val(h),b=!1,!1}var i=jQuery('input[name^="rtmedia-options[general_perPageMedia]"]');if(b&&i.length>0&&void 0!==i){var e="",j=0;if(i.val()<1?(e+=rtmedia_admin_strings.per_page_media_negative_value,j=10):jQuery.isNumeric(i.val())&&Math.floor(i.val())!=i.val()&&(e+=rtmedia_admin_strings.per_page_media_positive_error+" "+Math.round(i.val())+".",j=Math.round(i.val())),""!=e)return alert(e),i.val(j),b=!1,!1}b||a.preventDefault()}),jQuery(document).on("click","#bpm-services .encoding-try-now,#rtm-services .encoding-try-now",function(a){if(a.preventDefault(),confirm(rtmedia_admin_strings.are_you_sure)){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b));var b={action:"rtmedia_free_encoding_subscribe"};jQuery.getJSON(ajaxurl,b,function(a){if(void 0===a.error&&a.apikey){var b=window.location.href,c=window.location.hash;b=b.replace(c,""),document.location.href=b+"&apikey="+a.apikey+c}else{jQuery(".encoding-try-now").next().remove(),jQuery("#settings-error-encoding-error").remove();var d={id:"settings-error-encoding-error",msg:a.error,class:"error"};jQuery("#bp-media-settings-boxes").before(rtMediaAdmin.templates.rtm_msg_div(d))}})}}),jQuery(document).on("click","#api-key-submit",function(a){if(a.preventDefault(),0==jQuery(this).next("img").length){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b))}var b={action:"rtmedia_enter_api_key",apikey:jQuery("#new-api-key").val()};jQuery.getJSON(ajaxurl,b,function(a){if(void 0===a.error&&a.apikey){var b=window.location.href,c=window.location.hash;b=b.replace(c,""),-1==b.toString().indexOf("&apikey="+a.apikey)&&(b+="&apikey="+a.apikey),-1==b.toString().indexOf("&update=true")&&(b+="&update=true"),document.location.href=b+c}else{jQuery("#settings-error-api-key-error").remove();var d={id:"settings-error-api-key-error",msg:a.error,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(d))}jQuery("#api-key-submit").next("img").remove()})}),jQuery(document).on("click","#disable-encoding",function(a){if(a.preventDefault(),confirm(rtmedia_admin_strings.disable_encoding)){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b));var b={action:"rtmedia_disable_encoding"};jQuery.post(ajaxurl,b,function(a){if(a){if(jQuery(".settings-error-encoding-disabled").remove(),jQuery("#settings-encoding-successfully-updated").length>0)jQuery("#settings-encoding-successfully-updated p").html(a);else{var b={id:"settings-encoding-successfully-updated",msg:a,class:"updated"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}jQuery("#rtmedia-encoding-usage").hide(),jQuery("#disable-encoding").next("img").remove(),jQuery("#disable-encoding").hide(),jQuery("#enable-encoding").show()}else{jQuery("#settings-error-encoding-disabled").remove();var b={id:"settings-error-encoding-disabled",msg:rtmedia_admin_strings.something_went_wrong,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}})}}),jQuery(document).on("click","#enable-encoding",function(a){if(a.preventDefault(),confirm(rtmedia_admin_strings.enable_encoding)){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b));var b={action:"rtmedia_enable_encoding"};jQuery.post(ajaxurl,b,function(a){if(a){if(jQuery(".settings-error-encoding-enabled").remove(),jQuery("#settings-encoding-successfully-updated").length>0)jQuery("#settings-encoding-successfully-updated p").html(a);else{var b={id:"settings-encoding-successfully-updated",msg:a,class:"updated"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}jQuery("#enable-encoding").next("img").remove(),jQuery("#enable-encoding").hide(),jQuery("#disable-encoding").show()}else{jQuery("#settings-error-encoding-disabled").remove();var b={id:"settings-error-encoding-enabled",msg:rtmedia_admin_strings.something_went_wrong,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}})}}),jQuery(".bp-media-encoding-table").on("click",".bpm-unsubscribe",function(a){a.preventDefault(),jQuery("#bpm-unsubscribe-dialog").dialog({dialogClass:"wp-dialog",modal:!0,buttons:{Unsubscribe:function(){jQuery(this).dialog("close");var a={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(".bpm-unsubscribe").after(rtMediaAdmin.templates.rtm_image(a));var a={action:"rtmedia_unsubscribe_encoding_service",note:jQuery("#bpm-unsubscribe-note").val(),plan:jQuery(".bpm-unsubscribe").attr("data-plan"),price:jQuery(".bpm-unsubscribe").attr("data-price")};jQuery.getJSON(ajaxurl,a,function(a){if(void 0===a.error&&a.updated){jQuery(".bpm-unsubscribe").next().remove(),jQuery(".bpm-unsubscribe").after(a.form),jQuery(".bpm-unsubscribe").remove(),jQuery("#settings-unsubscribed-successfully").remove(),jQuery("#settings-unsubscribe-error").remove();var b={id:"settings-unsubscribed-successfully",msg:a.updated,class:"updated"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b)),window.location.hash="#settings-unsubscribed-successfully"}else{jQuery(".bpm-unsubscribe").next().remove(),jQuery("#settings-unsubscribed-successfully").remove(),jQuery("#settings-unsubscribe-error").remove();var b={id:"settings-unsubscribe-error",msg:a.error,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b)),window.location.hash="#settings-unsubscribe-error"}})}}})}),jQuery("#bpmedia-bpalbumimporter").on("change","#bp-album-import-accept",function(){jQuery(".bp-album-import-accept").toggleClass("i-accept"),jQuery(".bp-album-importer-wizard").slideToggle()}),jQuery("#rtprivacyinstall").click(function(a){a.preventDefault(),$progress_parent=jQuery("#rtprivacyinstaller"),$progress_parent.find(".rtprivacytype").each(function(){if($type=jQuery(this).attr("id"),"total"==$type){$values=[],jQuery(this).find("input").each(function(){$values[jQuery(this).attr("name")]=[jQuery(this).val()]}),$data={};for(var a=1;a<=$values.steps[0];a++)$count=20,a==$values.steps[0]&&($count=parseInt($values.laststep[0]),0==$count&&($count=20)),newvals={page:a,action:"rtmedia_privacy_install",count:$count,values:$values},$data[a]=newvals;var c=jQuery.Deferred();c.resolve(),jQuery.each($data,function(a,d){c=c.pipe(function(){return b(d)})})}})}),jQuery("#bpmedia-bpalbumimport-cleanup").click(function(a){a.preventDefault(),jQuery.post(ajaxurl,{action:"rtmedia_rt_album_cleanup",rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},function(a){window.location=settings_rt_album_import_url})}),jQuery("#bpmedia-bpalbumimporter").on("click","#bpmedia-bpalbumimport",function(a){if(a.preventDefault(),!jQuery("#bp-album-import-accept").prop("checked")){jQuery("html, body").animate({scrollTop:jQuery("#bp-album-import-accept").offset().top},500);var b=jQuery(".bp-album-import-accept"),d=3;return void function a(){b.css("background-color","#EE0000"),setTimeout(function(){b.css("background-color","#FFEBE8"),--d&&setTimeout(a,500)},500)}()}if(jQuery(this).prop("disabled",!0),wp_admin_url=ajaxurl.replace("admin-ajax.php",""),!jQuery(".bpm-ajax-loader").length){var e={src:rtmedia_admin_url+"images/wpspin_light.gif",class:"bpm-ajax-loader",norefresh:rtmedia_admin_strings.no_refresh};jQuery(this).after(rtMediaAdmin.templates.rtm_image(e))}$progress_parent=jQuery("#bpmedia-bpalbumimport"),$values=[],jQuery(this).parent().find("input").each(function(){$values[jQuery(this).attr("name")]=[jQuery(this).val()]}),0==$values.steps[0]&&($values.steps[0]=1),$data={};for(var d=1;d<=$values.steps[0];d++)$count=5,d==$values.steps[0]&&($count=parseInt($values.laststep[0]),0==$count&&($count=5)),newvals={page:d,action:"rtmedia_rt_album_import",count:$count,values:$values,rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},$data[d]=newvals;var f=jQuery.Deferred();f.resolve(),jQuery.each($data,function(a,b){f=f.pipe(function(){return c(b)})})}),jQuery("#bp-media-settings-boxes").on("click",".interested",function(){jQuery(".interested-container").removeClass("hidden"),jQuery(".choice-free").attr("required","required")}),jQuery("#bp-media-settings-boxes").on("click",".not-interested",function(){jQuery(".interested-container").addClass("hidden"),jQuery(".choice-free").removeAttr("required")}),jQuery("#video-transcoding-main-container").on("click",".video-transcoding-survey",function(a){a.preventDefault();var b={action:"rtmedia_convert_videos_form",email:jQuery(".email").val(),url:jQuery(".url").val(),choice:jQuery('input[name="choice"]:checked').val(),interested:jQuery('input[name="interested"]:checked').val()};return jQuery.post(ajaxurl,b,function(a){var b={msg:a,strong:"yes"};jQuery("#video-transcoding-main-container").html(rtMediaAdmin.templates.rtm_p_tag(b))}),!1}),jQuery("#bpmedia-bpalbumimporter").on("click",".deactivate-bp-album",function(a){a.preventDefault(),$bpalbum=jQuery(this);var b={action:"rtmedia_rt_album_deactivate",rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()};jQuery.get(ajaxurl,b,function(a){if(a)location.reload();else{var b={msg:rtmedia_admin_strings.something_went_wrong};$bpalbum.parent().after(rtMediaAdmin.templates.rtm_p_tag(b))}})}),jQuery(".updated").on("click",".bpm-hide-encoding-notice",function(){var a={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(a));var a={action:"rtmedia_hide_encoding_notice"};jQuery.post(ajaxurl,a,function(a){a&&jQuery(".bpm-hide-encoding-notice").closest(".updated").remove()})}),jQuery("#rtmedia-bp-enable-activity").is(":checked")?jQuery(".rtmedia-bp-activity-setting").prop("readonly",!1):jQuery(".rtmedia-bp-activity-setting").prop("readonly",!0),jQuery("#rtmedia-bp-enable-activity").on("click",function(a){jQuery(this).is(":checked")?jQuery(".rtmedia-bp-activity-setting").prop("readonly",!1):jQuery(".rtmedia-bp-activity-setting").prop("readonly",!0)});void 0!==rtmedia_on_label&&rtmedia_on_label,void 0!==rtmedia_off_label&&rtmedia_off_label;var j;jQuery("input[type=file]").on("change",f),jQuery("#rtmedia-submit-request").click(function(){var b=jQuery("#name").val(),c=jQuery("#email").val(),d=jQuery("#website").val(),e=jQuery("#subject").val(),f=jQuery("#details").val(),g=jQuery('input[name="request_type"]').val(),h=jQuery('input[name="request_id"]').val(),i=jQuery('input[name="server_address"]').val(),j=jQuery('input[name="ip_address"]').val(),k=jQuery('input[name="server_type"]').val(),l=jQuery('input[name="user_agent"]').val(),m=jQuery('input[name="debuglog_temp_path"]').val(),n={name:b,email:c,website:d,subject:e,details:f,request_id:h,request_type:"premium_support",server_address:i,ip_address:j,server_type:k,user_agent:l,debuglog_temp_path:m};if("bug_report"==g){var o=jQuery("#wp_admin_username").val();if(""==o)return alert(rtmedia_admin_support_strings.wp_admin_username_error),!1;var p=jQuery("#wp_admin_pwd").val();if(""==p)return alert(rtmedia_admin_support_strings.wp_admin_pwd_error),!1;var q=jQuery("#ssh_ftp_host").val();if(""==q)return alert(rtmedia_admin_support_strings.ssh_ftp_host_error),!1;var r=jQuery("#ssh_ftp_username").val();if(""==r)return alert(rtmedia_admin_support_strings.ssh_ftp_username_error),!1;var s=jQuery("#ssh_ftp_pwd").val();if(""==s)return alert(rtmedia_admin_support_strings.ssh_ftp_pwd_error),!1;n={name:b,email:c,website:d,subject:e,details:f,request_id:h,request_type:"premium_support",server_address:i,ip_address:j,server_type:k,user_agent:l,wp_admin_username:o,wp_admin_pwd:p,ssh_ftp_host:q,ssh_ftp_username:r,ssh_ftp_pwd:s}}for(formdata in n){if(""==n[formdata]&&"debuglog_temp_path"!=formdata)return alert("Please enter "+formdata.replace("_"," ")+" field."),!1;if(""==n[formdata]&&"debuglog_temp_path"==formdata)return alert("Please upload attachment."),!1}return data={action:"rtmedia_submit_request",form_data:n,support_wpnonce:jQuery("#support_wpnonce").val()},jQuery.post(ajaxurl,data,function(b){if("false"==(b=b.trim()))return alert(rtmedia_admin_support_strings.all_fields_error),!1;a("#rtmedia_service_contact_container").empty(),a("#rtmedia_service_contact_container").append(b)}),!1}),jQuery("#cancel-request").click(function(){return!1}),jQuery(".rtm_enable_masonry_view input[type=checkbox]").is(":checked")?jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").show():jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").hide(),jQuery(".rtm_enable_masonry_view input[type=checkbox]").on("click",function(a){jQuery(this).is(":checked")?jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").show():jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").hide()}),jQuery("#rtm-masonry-change-thumbnail-info").click(function(a){jQuery("html, body").animate({scrollTop:0},"500","swing")}),jQuery("#rtm-export-button").click(function(){data={action:"rtmedia_export_settings"},jQuery.post(ajaxurl,data,function(a){var b="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(a)),c=document.createElement("a");c.setAttribute("href",b),c.setAttribute("download","rtm-settings.json"),c.click(),c.remove()})}),jQuery("#rtm-export-data-button").click(function(){window.location.href="/wp-admin/tools.php?page=export_personal_data"}),jQuery("#rtm-erase-data-button").click(function(){window.location.href="/wp-admin/tools.php?page=remove_personal_data"})}),jQuery(window).load(function(){jQuery(".rtmedia-addon-thickbox").trigger("click")});
3
  * @package rtMedia
4
  */
5
 
6
+ function rtmedia_addon_do_not_show(){var a={action:"rtmedia_addon_popup_not_show_again"};jQuery.post(rtmedia_admin_ajax,a,function(a){jQuery("#TB_window").remove(),jQuery("#TB_overlay").remove()})}"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b}),function(a,b,c,d){var e={init:function(b,c){var d=this;d.elem=c,d.$elem=a(c),d.options=a.extend({},a.fn.rtTab.options,b),d.rtTabs()},rtTabs:function(){var c=this,d=c.options.activeTab;if(c.$elem.find("li:nth-child("+d+")").addClass("active"),c.rtTabContent(activeTabContent="yes"),c.rtClick(),!0==("false"!==c.$elem.attr("data-hash"))){var e=b.location.hash;e&&c.$elem.find("li").find('a[href="'+e+'"]').trigger("click"),a(b).on("hashchange",function(){var a=b.location.hash;c.$elem.find("li").find('a[href="'+a+'"]').trigger("click")})}},rtClick:function(){var c=this,d=c.$elem.find("li");d.find("a").on("click",function(e){e.preventDefault(),d.removeClass("active"),c.rtTabContent(),a(this).parent().addClass("active");var f=a(this).attr("href");if(a(f).removeClass("hide"),1==("false"!==c.$elem.attr("data-hash"))){var g=a(b).scrollTop();location.hash=a(this).attr("href"),a(b).scrollTop(g)}"function"==typeof c.options.onComplete&&c.options.onComplete.apply(c.elem,arguments)})},rtTabContent:function(b){this.$elem.find("li").find("a").each(function(){var c=a(this),d=c.attr("href");"yes"===b?c.parent().hasClass("active")||a(d).addClass("hide"):a(d).addClass("hide")})}};a.fn.rtTab=function(b){return this.each(function(){var c=Object.create(e);c.init(b,this),a.data(this,"rtTab",c)})},a.fn.rtTab.options={activeTab:1,onComplete:null}}(jQuery,window,document),jQuery(document).ready(function(a){var b=document.createElement("div");b.setAttribute("class","rtm-warning rtm-fly-warning hide"),a(".rtm-tabs").rtTab(),a('input[name^="rtmedia-options"]').on("change",function(){a(".rtm-save-settings-msg").remove(),0===a(".rtm-fly-warning").length&&(b.innerText=rtmedia_admin_strings.settings_changed,a(".rtm-button-container.top").prepend(b),a(".rtm-fly-warning").slideDown())}),a(".rtm-img-size-setting .form-table tr:nth-child(7) td:last-child").attr("colspan","3"),a(".rtm-field-wrap .switch input[type=checkbox]").each(function(){var b=a(this);b.parents("table").attr("data-depends")||(b.is(":checked")?(b.parents("table").next(".rtm-notice").slideDown(),b.parents("table").siblings("table").each(function(){a(this).attr("data-depends")&&a(this).slideDown()})):(b.parents("table").next(".rtm-notice").slideUp(),b.parents("table").siblings("table").each(function(){a(this).attr("data-depends")&&a(this).slideUp()}))),b.parents("tr").next("tr").attr("data-depends")&&(b.is(":checked")?b.parents("tr").next("tr").slideDown():b.parents("tr").next("tr").slideUp())}),a(".rtm-field-wrap .switch input[type=checkbox]").on("change",function(){var b=a(this);b.parents("table").attr("data-depends")||(b.parents("table").next(".rtm-notice").slideToggle(),b.parents("table").siblings("table").each(function(){a(this).attr("data-depends")&&a(this).slideToggle()})),b.parents("tr").next("tr").attr("data-depends")&&b.parents("tr").next("tr").slideToggle()});var c=Backbone.View.extend({el:a(".bp-media-admin"),events:{"click .rtm-theme":"render","click .rtm-close":"close","click .rtm-previous":"previousTheme","click .rtm-next":"nextTheme",keyup:"keyEvent"},initialize:function(){_.bindAll(this,"render","close","nextTheme","previousTheme","keyEvent"),this.keyEvent()},render:function(b){a(".rtm-theme").removeClass("rtm-modal-open");var c=a(b.currentTarget).addClass("rtm-modal-open").find(".rtm-theme-content").html();if(a(".rtm-theme-overlay")[0])a(".rtm-theme-overlay").show(),a(this.el).find(".rtm-theme-content-wrap").empty().append(c);else{var d={themeContent:c};a(this.el).append(rtMediaAdmin.templates.rtm_theme_overlay(d))}a(b.currentTarget).is(":first-child")?a(".rtm-previous").addClass("disabled"):a(b.currentTarget).is(":last-child")?a(".rtm-next").addClass("disabled"):a(".rtm-next, .rtm-previous").removeClass("disabled")},close:function(){a(".rtm-theme").removeClass("rtm-modal-open"),a(".rtm-theme-overlay").hide(),a(".rtm-next, .rtm-previous").removeClass("disabled")},nextTheme:function(b){return a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:last-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").next().trigger("click"),!1},previousTheme:function(b){return a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:first-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").prev().trigger("click"),!1},keyEvent:function(){a("body").on("keyup",function(b){return 39===b.keyCode?(a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:last-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").next().trigger("click"),!1):37===b.keyCode?(a(".rtm-next, .rtm-previous").removeClass("disabled"),a(".rtm-theme:first-child").hasClass("rtm-modal-open")&&a(b.currentTarget).addClass("disabled"),a(".rtm-modal-open").prev().trigger("click"),!1):void(27===b.keyCode&&a(".rtm-close").trigger("click"))})}});new c;jQuery("#rtm-licenses .regular-text").each(function(){jQuery(this).keypress(function(a){if("13"==(a.keyCode?a.keyCode:a.which))return!1})}),jQuery("#bp_media_settings_form").on("submit",function(a){jQuery("#rtcss-notice").remove();var b=jQuery("#rtmedia-custom-css").val(),c=b.match(/@import\s*(url)?\s*\(?([^;]+?)\)?;/);if(null!=c){if(null!=c[0])return jQuery("#rtmedia-custom-css").after('<div id="rtcss-notice" class="error"><p>'+rtmedia_admin_strings.wrong_css_input+"</p></div>"),!1}})});var rtMediaAdmin=new Object;rtMediaAdmin.templates={rtm_image:wp.template("rtm-image"),rtm_msg_div:wp.template("rtm-msg-div"),rtm_album_favourites_importer:wp.template("rtm-album-favourites-importer"),rtm_map_mapping_failure:wp.template("rtm-map-mapping-failure"),rtm_p_tag:wp.template("rtm-p-tag"),rtm_theme_overlay:wp.template("rtm-theme-overlay")},jQuery(document).ready(function(a){function b(a){return jQuery.post(ajaxurl,a,function(b){if(0!=b){var c=!1,d=Math.ceil((20*parseInt(b)+parseInt(a.values.finished))/parseInt(a.values.total)*100);d>100&&(d=100,c=!0),jQuery("#rtprogressbar>div").css("width",d+"%"),finished=jQuery("#rtprivacyinstaller span.finished").html(),jQuery("#rtprivacyinstaller span.finished").html(parseInt(finished)+a.count),c&&jQuery.post(ajaxurl,{action:"rtmedia_privacy_redirect"},function(a){window.location=settings_url})}else{var e={msg:"Row "+b+" failed."};jQuery("#map_progress_msgs").html(rtMediaAdmin.templates.rtm_map_mapping_failure(e))}})}function c(a){return jQuery.getJSON(ajaxurl,a,function(b){if(favorites=!1,b){var c=Math.ceil((5*parseInt(b.page)+parseInt(a.values.finished))/parseInt(a.values.total)*100);comments_total=jQuery("#bpmedia-bpalbumimporter .bp-album-comments span.total").html(),users_total=jQuery("#bpmedia-bpalbumimporter .bp-album-users span.total").html(),media_total=jQuery("#bpmedia-bpalbumimporter .bp-album-media span.total").html(),comments_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-comments span.finished").html(),users_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-users span.finished").html();var f=Math.ceil((parseInt(b.comments)+parseInt(comments_finished))/parseInt(comments_total)*100),g=Math.ceil(parseInt(b.users)/parseInt(users_total)*100);(c>100||100==c)&&(c=100,favorites=!0),jQuery(".bp-album-media #rtprogressbar>div").css("width",c+"%"),jQuery(".bp-album-comments #rtprogressbar>div").css("width",f+"%"),jQuery(".bp-album-users #rtprogressbar>div").css("width",g+"%"),media_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-media span.finished").html(),parseInt(media_finished)<parseInt(media_total)&&jQuery("#bpmedia-bpalbumimporter .bp-album-media span.finished").html(parseInt(media_finished)+a.count),jQuery("#bpmedia-bpalbumimporter .bp-album-comments span.finished").html(parseInt(b.comments)+parseInt(comments_finished)),jQuery("#bpmedia-bpalbumimporter .bp-album-users span.finished").html(parseInt(b.users)),favorites&&(favorite_data={action:"rtmedia_rt_album_import_favorites",rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},jQuery.post(ajaxurl,favorite_data,function(a){if(!a.hasOwnProperty(favorites)||0===a.favorites&&"0"===a.favorites)window.setTimeout(e,2e3);else{if(!jQuery(".bp-album-favorites").length){var b={users:a.users};jQuery(".bp-album-comments").after(rtMediaAdmin.templates.rtm_album_favourites_importer(b))}$favorites={},0!=a.offset||"0"!=a.offset?start=1*a.offset+1:start=1;for(var c=start;c<=a.users;c++)$count=1,c==a.users&&($count=parseInt(a.users%$count),0==$count&&($count=1)),newvals={action:"rtmedia_rt_album_import_step_favorites",offset:1*(c-1),redirect:c==a.users,rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},$favorites[c]=newvals;var f=jQuery.Deferred();f.resolve(),jQuery.each($favorites,function(a,b){f=f.pipe(function(){return d(b)})})}},"json"))}else if(a.hasOwnProperty(page)){var h={msg:"Row "+b.page+" failed."};jQuery("#map_progress_msgs").html(rtMediaAdmin.templates.rtm_map_mapping_failure(h))}else{var h={msg:rtmedia_admin_strings.request_failed};jQuery("#map_progress_msgs").html(rtMediaAdmin.templates.rtm_map_mapping_failure(h))}})}function d(a){return jQuery.post(ajaxurl,a,function(a){redirect=!1,favorites_total=jQuery("#bpmedia-bpalbumimporter .bp-album-favorites span.total").html(),favorites_finished=jQuery("#bpmedia-bpalbumimporter .bp-album-favorites span.finished").html(),jQuery("#bpmedia-bpalbumimporter .bp-album-favorites span.finished").html(parseInt(favorites_finished)+1);var b=Math.ceil(parseInt(favorites_finished+1)/parseInt(favorites_total)*100);(b>100||100==b)&&(b=100,redirect=!0),jQuery(".bp-album-favorites #rtprogressbar>div").css("width",b+"%"),redirect&&window.setTimeout(e,2e3)})}function e(){window.location=document.URL}function f(a){j=a.target.files,g(a)}function g(a){a.stopPropagation(),a.preventDefault();var b=new FormData;void 0!==a&&void 0!==a.target&&void 0!==a.target.name&&"rtFileInput"===a.target.name&&b.append("import_export_control",a.target.name),jQuery.each(j,function(a,c){b.append(a,c)});var c=jQuery("#rtmedia_admin_upload_nonce").val();void 0!==c&&""!==c&&b.append("rtmedia_admin_upload_nonce",c),b.append("action","rtmedia_admin_upload"),jQuery.ajax({url:rtmedia_admin_ajax,type:"POST",data:b,cache:!1,processData:!1,contentType:!1,success:function(a){if(a.hasOwnProperty("rtm_response")&&a.hasOwnProperty("rtm_response_msg")){jQuery("#rtm-setting-msg").remove();var b=jQuery("<div/>",{id:"rtm-setting-msg",class:"rtm-fly-warning"});"success"===a.rtm_response?(b.addClass("rtm-success rtm-save-settings-msg"),b.text(a.rtm_response_msg),jQuery(".rtm-button-container.top").append(b),location.reload()):"error"===a.rtm_response&&(b.addClass("rtm-warning"),b.text(a.rtm_response_msg),jQuery(".rtm-button-container.top").append(b),b.delay(3e3).fadeOut(100))}if(void 0===a.error){if(a.exceed_size_msg)return jQuery("#debuglog").val(""),alert(a.exceed_size_msg),!1;jQuery("#debuglog_temp_path").val(a.debug_attachmanet)}else jQuery("#debuglog").val(""),alert("ERRORS: "+a.error)}})}var h=a("#rtm-licenses");h.length>0&&h.find(".license-inner:first input:first").focus();var i=document.createElement("div");i.className="support_form_loader",a(".rtm-save-settings-msg").length>0&&setTimeout(function(){a(".rtm-save-settings-msg").remove()},1e4),jQuery("#spread-the-word").on("click","#bp-media-add-linkback",function(){var a={action:"rtmedia_linkback",linkback:jQuery("#bp-media-add-linkback:checked").length};jQuery.post(rtmedia_admin_ajax,a,function(a){})}),jQuery("#bp-media-settings-boxes").on("change","#select-request",function(){if(jQuery(this).val()){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(i);var a={action:"rtmedia_select_request",form:jQuery(this).val()};jQuery.post(ajaxurl,a,function(a){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(a).fadeIn("slow")})}}),jQuery("#bp-media-settings-boxes").on("click","#cancel-request",function(){if(jQuery(this).val()){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(i);var a={action:"rtmedia_cancel_request"};jQuery.post(ajaxurl,a,function(a){jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(),jQuery("#bp_media_settings_form .bp-media-metabox-holder").html(a).fadeIn("slow")})}}),jQuery("#bp-media-settings-boxes").on("submit","#bp_media_settings_form, .rtmedia-settings-submit",function(a){var b=!0,c=new RegExp("^[0-9]+$");jQuery("input[name*='defaultSizes']").each(function(a){if(!c.test(jQuery(this).val()))return alert("Invalid value for "+jQuery(this).attr("name").replace("rtmedia-options[defaultSizes_","").replace("]","").replace(/_/g," ").replace(/(\b)([a-zA-Z] )/g,function(a){return a.toUpperCase()})),b=!1,!1});var d=jQuery('input[name^="rtmedia-options[general_videothumbs]"]');if(b&&d.length>0&&void 0!==d){var e="",f=0;if(d.val()<=0?(e+=rtmedia_admin_strings.video_thumbnail_error,f=2):c.test(d.val())||(e+=rtmedia_admin_strings.video_thumbnail_invalid_value+" "+Math.round(d.val())+".",f=Math.round(d.val())),""!=e)return alert(e),d.val(f),b=!1,!1}var g=jQuery('input[name^="rtmedia-options[general_jpeg_image_quality]"]');if(b&&g.length>0&&void 0!==g){var e="",h=0;if(g.val()<=0?(e+=rtmedia_admin_strings.jpeg_quality_negative_error,h=90):g.val()>100?(e+=rtmedia_admin_strings.jpeg_quality_percentage_error,h=100):c.test(g.val())||(e+=rtmedia_admin_strings.jpeg_quality_invalid_value+" "+Math.round(g.val())+".",h=Math.round(g.val())),""!=e)return alert(e),g.val(h),b=!1,!1}var i=jQuery('input[name^="rtmedia-options[general_perPageMedia]"]');if(b&&i.length>0&&void 0!==i){var e="",j=0;if(i.val()<1?(e+=rtmedia_admin_strings.per_page_media_negative_value,j=10):jQuery.isNumeric(i.val())&&Math.floor(i.val())!=i.val()&&(e+=rtmedia_admin_strings.per_page_media_positive_error+" "+Math.round(i.val())+".",j=Math.round(i.val())),""!=e)return alert(e),i.val(j),b=!1,!1}b||a.preventDefault()}),jQuery(document).on("click","#bpm-services .encoding-try-now,#rtm-services .encoding-try-now",function(a){if(a.preventDefault(),confirm(rtmedia_admin_strings.are_you_sure)){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b));var b={action:"rtmedia_free_encoding_subscribe"};jQuery.getJSON(ajaxurl,b,function(a){if(void 0===a.error&&a.apikey){var b=window.location.href,c=window.location.hash;b=b.replace(c,""),document.location.href=b+"&apikey="+a.apikey+c}else{jQuery(".encoding-try-now").next().remove(),jQuery("#settings-error-encoding-error").remove();var d={id:"settings-error-encoding-error",msg:a.error,class:"error"};jQuery("#bp-media-settings-boxes").before(rtMediaAdmin.templates.rtm_msg_div(d))}})}}),jQuery(document).on("click","#api-key-submit",function(a){if(a.preventDefault(),0==jQuery(this).next("img").length){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b))}var b={action:"rtmedia_enter_api_key",apikey:jQuery("#new-api-key").val()};jQuery.getJSON(ajaxurl,b,function(a){if(void 0===a.error&&a.apikey){var b=window.location.href,c=window.location.hash;b=b.replace(c,""),-1==b.toString().indexOf("&apikey="+a.apikey)&&(b+="&apikey="+a.apikey),-1==b.toString().indexOf("&update=true")&&(b+="&update=true"),document.location.href=b+c}else{jQuery("#settings-error-api-key-error").remove();var d={id:"settings-error-api-key-error",msg:a.error,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(d))}jQuery("#api-key-submit").next("img").remove()})}),jQuery(document).on("click","#disable-encoding",function(a){if(a.preventDefault(),confirm(rtmedia_admin_strings.disable_encoding)){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b));var b={action:"rtmedia_disable_encoding"};jQuery.post(ajaxurl,b,function(a){if(a){if(jQuery(".settings-error-encoding-disabled").remove(),jQuery("#settings-encoding-successfully-updated").length>0)jQuery("#settings-encoding-successfully-updated p").html(a);else{var b={id:"settings-encoding-successfully-updated",msg:a,class:"updated"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}jQuery("#rtmedia-encoding-usage").hide(),jQuery("#disable-encoding").next("img").remove(),jQuery("#disable-encoding").hide(),jQuery("#enable-encoding").show()}else{jQuery("#settings-error-encoding-disabled").remove();var b={id:"settings-error-encoding-disabled",msg:rtmedia_admin_strings.something_went_wrong,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}})}}),jQuery(document).on("click","#enable-encoding",function(a){if(a.preventDefault(),confirm(rtmedia_admin_strings.enable_encoding)){var b={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(b));var b={action:"rtmedia_enable_encoding"};jQuery.post(ajaxurl,b,function(a){if(a){if(jQuery(".settings-error-encoding-enabled").remove(),jQuery("#settings-encoding-successfully-updated").length>0)jQuery("#settings-encoding-successfully-updated p").html(a);else{var b={id:"settings-encoding-successfully-updated",msg:a,class:"updated"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}jQuery("#enable-encoding").next("img").remove(),jQuery("#enable-encoding").hide(),jQuery("#disable-encoding").show()}else{jQuery("#settings-error-encoding-disabled").remove();var b={id:"settings-error-encoding-enabled",msg:rtmedia_admin_strings.something_went_wrong,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b))}})}}),jQuery(".bp-media-encoding-table").on("click",".bpm-unsubscribe",function(a){a.preventDefault(),jQuery("#bpm-unsubscribe-dialog").dialog({dialogClass:"wp-dialog",modal:!0,buttons:{Unsubscribe:function(){jQuery(this).dialog("close");var a={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(".bpm-unsubscribe").after(rtMediaAdmin.templates.rtm_image(a));var a={action:"rtmedia_unsubscribe_encoding_service",note:jQuery("#bpm-unsubscribe-note").val(),plan:jQuery(".bpm-unsubscribe").attr("data-plan"),price:jQuery(".bpm-unsubscribe").attr("data-price")};jQuery.getJSON(ajaxurl,a,function(a){if(void 0===a.error&&a.updated){jQuery(".bpm-unsubscribe").next().remove(),jQuery(".bpm-unsubscribe").after(a.form),jQuery(".bpm-unsubscribe").remove(),jQuery("#settings-unsubscribed-successfully").remove(),jQuery("#settings-unsubscribe-error").remove();var b={id:"settings-unsubscribed-successfully",msg:a.updated,class:"updated"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b)),window.location.hash="#settings-unsubscribed-successfully"}else{jQuery(".bpm-unsubscribe").next().remove(),jQuery("#settings-unsubscribed-successfully").remove(),jQuery("#settings-unsubscribe-error").remove();var b={id:"settings-unsubscribe-error",msg:a.error,class:"error"};jQuery("h2:first").after(rtMediaAdmin.templates.rtm_msg_div(b)),window.location.hash="#settings-unsubscribe-error"}})}}})}),jQuery("#bpmedia-bpalbumimporter").on("change","#bp-album-import-accept",function(){jQuery(".bp-album-import-accept").toggleClass("i-accept"),jQuery(".bp-album-importer-wizard").slideToggle()}),jQuery("#rtprivacyinstall").click(function(a){a.preventDefault(),$progress_parent=jQuery("#rtprivacyinstaller"),$progress_parent.find(".rtprivacytype").each(function(){if($type=jQuery(this).attr("id"),"total"==$type){$values=[],jQuery(this).find("input").each(function(){$values[jQuery(this).attr("name")]=[jQuery(this).val()]}),$data={};for(var a=1;a<=$values.steps[0];a++)$count=20,a==$values.steps[0]&&($count=parseInt($values.laststep[0]),0==$count&&($count=20)),newvals={page:a,action:"rtmedia_privacy_install",count:$count,values:$values},$data[a]=newvals;var c=jQuery.Deferred();c.resolve(),jQuery.each($data,function(a,d){c=c.pipe(function(){return b(d)})})}})}),jQuery("#bpmedia-bpalbumimport-cleanup").click(function(a){a.preventDefault(),jQuery.post(ajaxurl,{action:"rtmedia_rt_album_cleanup",rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},function(a){window.location=settings_rt_album_import_url})}),jQuery("#bpmedia-bpalbumimporter").on("click","#bpmedia-bpalbumimport",function(a){if(a.preventDefault(),!jQuery("#bp-album-import-accept").prop("checked")){jQuery("html, body").animate({scrollTop:jQuery("#bp-album-import-accept").offset().top},500);var b=jQuery(".bp-album-import-accept"),d=3;return void function a(){b.css("background-color","#EE0000"),setTimeout(function(){b.css("background-color","#FFEBE8"),--d&&setTimeout(a,500)},500)}()}if(jQuery(this).prop("disabled",!0),wp_admin_url=ajaxurl.replace("admin-ajax.php",""),!jQuery(".bpm-ajax-loader").length){var e={src:rtmedia_admin_url+"images/wpspin_light.gif",class:"bpm-ajax-loader",norefresh:rtmedia_admin_strings.no_refresh};jQuery(this).after(rtMediaAdmin.templates.rtm_image(e))}$progress_parent=jQuery("#bpmedia-bpalbumimport"),$values=[],jQuery(this).parent().find("input").each(function(){$values[jQuery(this).attr("name")]=[jQuery(this).val()]}),0==$values.steps[0]&&($values.steps[0]=1),$data={};for(var d=1;d<=$values.steps[0];d++)$count=5,d==$values.steps[0]&&($count=parseInt($values.laststep[0]),0==$count&&($count=5)),newvals={page:d,action:"rtmedia_rt_album_import",count:$count,values:$values,rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()},$data[d]=newvals;var f=jQuery.Deferred();f.resolve(),jQuery.each($data,function(a,b){f=f.pipe(function(){return c(b)})})}),jQuery("#bp-media-settings-boxes").on("click",".interested",function(){jQuery(".interested-container").removeClass("hidden"),jQuery(".choice-free").attr("required","required")}),jQuery("#bp-media-settings-boxes").on("click",".not-interested",function(){jQuery(".interested-container").addClass("hidden"),jQuery(".choice-free").removeAttr("required")}),jQuery("#video-transcoding-main-container").on("click",".video-transcoding-survey",function(a){a.preventDefault();var b={action:"rtmedia_convert_videos_form",email:jQuery(".email").val(),url:jQuery(".url").val(),choice:jQuery('input[name="choice"]:checked').val(),interested:jQuery('input[name="interested"]:checked').val()};return jQuery.post(ajaxurl,b,function(a){var b={msg:a,strong:"yes"};jQuery("#video-transcoding-main-container").html(rtMediaAdmin.templates.rtm_p_tag(b))}),!1}),jQuery("#bpmedia-bpalbumimporter").on("click",".deactivate-bp-album",function(a){a.preventDefault(),$bpalbum=jQuery(this);var b={action:"rtmedia_rt_album_deactivate",rtm_wpnonce:jQuery("#bpaimporter_wpnonce").val()};jQuery.get(ajaxurl,b,function(a){if(a)location.reload();else{var b={msg:rtmedia_admin_strings.something_went_wrong};$bpalbum.parent().after(rtMediaAdmin.templates.rtm_p_tag(b))}})}),jQuery(".updated").on("click",".bpm-hide-encoding-notice",function(){var a={src:rtmedia_admin_url+"images/wpspin_light.gif"};jQuery(this).after(rtMediaAdmin.templates.rtm_image(a));var a={action:"rtmedia_hide_encoding_notice"};jQuery.post(ajaxurl,a,function(a){a&&jQuery(".bpm-hide-encoding-notice").closest(".updated").remove()})}),jQuery("#rtmedia-bp-enable-activity").is(":checked")?jQuery(".rtmedia-bp-activity-setting").prop("readonly",!1):jQuery(".rtmedia-bp-activity-setting").prop("readonly",!0),jQuery("#rtmedia-bp-enable-activity").on("click",function(a){jQuery(this).is(":checked")?jQuery(".rtmedia-bp-activity-setting").prop("readonly",!1):jQuery(".rtmedia-bp-activity-setting").prop("readonly",!0)});void 0!==rtmedia_on_label&&rtmedia_on_label,void 0!==rtmedia_off_label&&rtmedia_off_label;var j;jQuery("input[type=file]").on("change",f),jQuery("#rtmedia-submit-request").click(function(){var b=jQuery("#name").val(),c=jQuery("#email").val(),d=jQuery("#website").val(),e=jQuery("#subject").val(),f=jQuery("#details").val(),g=jQuery('input[name="request_type"]').val(),h=jQuery('input[name="request_id"]').val(),i=jQuery('input[name="server_address"]').val(),j=jQuery('input[name="ip_address"]').val(),k=jQuery('input[name="server_type"]').val(),l=jQuery('input[name="user_agent"]').val(),m=jQuery('input[name="debuglog_temp_path"]').val(),n={name:b,email:c,website:d,subject:e,details:f,request_id:h,request_type:"premium_support",server_address:i,ip_address:j,server_type:k,user_agent:l,debuglog_temp_path:m};if("bug_report"==g){var o=jQuery("#wp_admin_username").val();if(""==o)return alert(rtmedia_admin_support_strings.wp_admin_username_error),!1;var p=jQuery("#wp_admin_pwd").val();if(""==p)return alert(rtmedia_admin_support_strings.wp_admin_pwd_error),!1;var q=jQuery("#ssh_ftp_host").val();if(""==q)return alert(rtmedia_admin_support_strings.ssh_ftp_host_error),!1;var r=jQuery("#ssh_ftp_username").val();if(""==r)return alert(rtmedia_admin_support_strings.ssh_ftp_username_error),!1;var s=jQuery("#ssh_ftp_pwd").val();if(""==s)return alert(rtmedia_admin_support_strings.ssh_ftp_pwd_error),!1;n={name:b,email:c,website:d,subject:e,details:f,request_id:h,request_type:"premium_support",server_address:i,ip_address:j,server_type:k,user_agent:l,wp_admin_username:o,wp_admin_pwd:p,ssh_ftp_host:q,ssh_ftp_username:r,ssh_ftp_pwd:s}}for(formdata in n){if(""==n[formdata]&&"debuglog_temp_path"!=formdata)return alert("Please enter "+formdata.replace("_"," ")+" field."),!1;if(""==n[formdata]&&"debuglog_temp_path"==formdata)return alert("Please upload attachment."),!1}return data={action:"rtmedia_submit_request",form_data:n,support_wpnonce:jQuery("#support_wpnonce").val()},jQuery.post(ajaxurl,data,function(b){if("false"==(b=b.trim()))return alert(rtmedia_admin_support_strings.all_fields_error),!1;a("#rtmedia_service_contact_container").empty(),a("#rtmedia_service_contact_container").append(b)}),!1}),jQuery("#cancel-request").click(function(){return!1}),jQuery(".rtm_enable_masonry_view input[type=checkbox]").is(":checked")?jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").show():jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").hide(),jQuery(".rtm_enable_masonry_view input[type=checkbox]").on("click",function(a){jQuery(this).is(":checked")?jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").show():jQuery(".rtm_enable_masonry_view").parents(".metabox-holder").find(".rtmedia-info").hide()}),jQuery("#rtm-masonry-change-thumbnail-info").click(function(a){jQuery("html, body").animate({scrollTop:0},"500","swing")}),jQuery("#rtm-export-button").click(function(){data={action:"rtmedia_export_settings"},jQuery.post(ajaxurl,data,function(a){var b="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(a)),c=document.createElement("a");c.setAttribute("href",b),c.setAttribute("download","rtm-settings.json"),jQuery("body").append(c),c.click(),c.remove()})}),jQuery("#rtm-export-data-button").click(function(){window.location.href="/wp-admin/tools.php?page=export_personal_data"}),jQuery("#rtm-erase-data-button").click(function(){window.location.href="/wp-admin/tools.php?page=remove_personal_data"})}),jQuery(window).load(function(){jQuery(".rtmedia-addon-thickbox").trigger("click")});
app/assets/admin/js/settings.js CHANGED
@@ -965,6 +965,7 @@ jQuery( document ).ready( function ( $ ) {
965
  var downloadAnchorNode = document.createElement( 'a' );
966
  downloadAnchorNode.setAttribute( 'href', dataStr );
967
  downloadAnchorNode.setAttribute( 'download', 'rtm-settings.json' );
 
968
  downloadAnchorNode.click();
969
  downloadAnchorNode.remove();
970
  } );
965
  var downloadAnchorNode = document.createElement( 'a' );
966
  downloadAnchorNode.setAttribute( 'href', dataStr );
967
  downloadAnchorNode.setAttribute( 'download', 'rtm-settings.json' );
968
+ jQuery( 'body' ).append( downloadAnchorNode );
969
  downloadAnchorNode.click();
970
  downloadAnchorNode.remove();
971
  } );
app/assets/css/rtmedia.css CHANGED
@@ -343,6 +343,9 @@ button#rtmedia-add-media-button-post-update .dashicons {
343
  #buddypress a.rtm-button-back {
344
  padding: 3px 10px;
345
  }
 
 
 
346
 
347
  .rtmedia_next_prev {
348
  padding: 0 10px;
@@ -359,6 +362,10 @@ button#rtmedia-add-media-button-post-update .dashicons {
359
  .rtm-page-number .rtmedia-page-link {
360
  float: left;
361
  }
 
 
 
 
362
 
363
  .rtm-pagination {
364
  background: transparent;
@@ -398,7 +405,7 @@ button#rtmedia-add-media-button-post-update .dashicons {
398
  #rtmedia_go_to_num {
399
  font-size: 16px;
400
  margin: 0 5px;
401
- padding: 4px 5px;
402
  width: 80px;
403
  }
404
 
@@ -1160,7 +1167,7 @@ img.mfp-img {
1160
  /*
1161
  * popup autocomplete
1162
  */
1163
- #atwho-container #atwho-ground-comment_content .atwho-view {
1164
  z-index: 2147483647;
1165
  }
1166
 
@@ -1260,10 +1267,6 @@ img.mfp-img {
1260
  padding: 0 4px 0 0;
1261
  }
1262
 
1263
- #buddypress #rtm-media-options-list .rtm-options form button {
1264
- font-size: small;
1265
- }
1266
-
1267
  #buddypress #rtm-media-options-list .rtm-options .button {
1268
  background: transparent;
1269
  border: 0 none;
@@ -1274,13 +1277,18 @@ img.mfp-img {
1274
  font-weight: normal;
1275
  line-height: 24px;
1276
  padding: 0 6px;
1277
- text-shadow: 0 0 0;
1278
  text-transform: none;
1279
  }
1280
  #buddypress #rtm-media-options-list .rtm-options .rtmedia-delete-favlist {
1281
  color: #FFFFFF;
1282
  padding: 0;
1283
  }
 
 
 
 
 
 
1284
 
1285
  .rtm-options.rtm-options {
1286
  background: #666666;
@@ -2596,6 +2604,10 @@ body div.bp_members.bp_member .entry-content {
2596
  display: none;
2597
  }
2598
 
 
 
 
 
2599
  .rtmedia-uploader .drag-drop {
2600
  border: 4px dashed #DDD;
2601
  text-align: center;
343
  #buddypress a.rtm-button-back {
344
  padding: 3px 10px;
345
  }
346
+ #buddypress div.rtmedia-page-no.rtm-page-number a.rtmedia-page-link.button {
347
+ padding: 5px 10px;
348
+ }
349
 
350
  .rtmedia_next_prev {
351
  padding: 0 10px;
362
  .rtm-page-number .rtmedia-page-link {
363
  float: left;
364
  }
365
+ .rtm-page-number .rtm-go-to-num,
366
+ .rtm-page-number .rtmedia-page-link {
367
+ line-height: 1.5;
368
+ }
369
 
370
  .rtm-pagination {
371
  background: transparent;
405
  #rtmedia_go_to_num {
406
  font-size: 16px;
407
  margin: 0 5px;
408
+ padding: 3px 5px;
409
  width: 80px;
410
  }
411
 
1167
  /*
1168
  * popup autocomplete
1169
  */
1170
+ .atwho-container #atwho-ground-comment_content .atwho-view {
1171
  z-index: 2147483647;
1172
  }
1173
 
1267
  padding: 0 4px 0 0;
1268
  }
1269
 
 
 
 
 
1270
  #buddypress #rtm-media-options-list .rtm-options .button {
1271
  background: transparent;
1272
  border: 0 none;
1277
  font-weight: normal;
1278
  line-height: 24px;
1279
  padding: 0 6px;
 
1280
  text-transform: none;
1281
  }
1282
  #buddypress #rtm-media-options-list .rtm-options .rtmedia-delete-favlist {
1283
  color: #FFFFFF;
1284
  padding: 0;
1285
  }
1286
+ #buddypress #rtm-media-options-list .rtm-options form button {
1287
+ font-size: 14px;
1288
+ }
1289
+ #buddypress #rtm-media-options-list .rtm-options i {
1290
+ line-height: 1.7;
1291
+ }
1292
 
1293
  .rtm-options.rtm-options {
1294
  background: #666666;
2604
  display: none;
2605
  }
2606
 
2607
+ h2.rtm-gallery-title {
2608
+ margin: 10px 0;
2609
+ }
2610
+
2611
  .rtmedia-uploader .drag-drop {
2612
  border: 4px dashed #DDD;
2613
  text-align: center;
app/assets/css/rtmedia.min.css CHANGED
@@ -1 +1 @@
1
- .alignleft{float:left}.alignright{float:right}.aligncenter{display:block;margin-left:auto;margin-right:auto;text-align:center}.clear-both{clear:both}.clear-none{clear:none}.clear-left{clear:left}.clear-right{clear:right}.rtm-inline-block{display:inline-block}.rtm-text-left{text-align:left}.rtm-text-right{text-align:right}.rtm-text-center{text-align:center}.rtm-border-0{border:0 !important}.hide{display:none}.rtmedia-success,.rtmedia-warning{margin:10px 0;padding:8px 14px 8px 14px;text-shadow:0 1px 0 rgba(255,255,255,0.5);border-bottom:1px solid #e7e7e7;cursor:pointer}.rtmedia-success{background-color:#dff0d8;color:#468847}.rtmedia-warning{background-color:#F0D8DD;color:#884646}.clearfix:after{content:"";display:table;clear:both}#buddypress form#whats-new-form textarea{box-sizing:border-box;min-height:70px;width:100%}#buddypress #whats-new-form .rtmedia-uploader-div{display:none}#buddypress #whats-new-form #whats-new-options .rtmedia-uploader-div{display:block}#buddypress #whats-new-options{height:auto !important;overflow:hidden}#buddypress form#whats-new-form p.activity-greeting{line-height:1}#buddypress form#whats-new-form #whats-new-options select{border:1px solid #ccc;font-size:13px;margin-top:0;padding:3px 2px}#whats-new-submit #aw-whats-new-submit{font-size:12px;line-height:18px;padding:4px 6px}#whats-new-post-in-box{float:left;font-size:13px}#buddypress form#whats-new-form #whats-new-submit{margin-top:0}#whats-new-textarea{margin-bottom:10px}body.media.buddypress{overflow-y:auto}#buddypress input[type=submit]:focus{background:#ededed;border:1px solid #bbb;color:#555;outline:0;text-decoration:none}#buddypress ul.activity-list li.activity-item .activity-comments .rtmedia-uploader-div{color:#767676;margin-left:50px;padding-left:15px}#buddypress form#whats-new-form #whats-new-content.active #whats-new-options[style] #whats-new-post-in-box{margin-top:0}#whats-new-post-in-box{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.rtmedia-container{box-sizing:border-box}.rtmedia-container *,.rtmedia-container *:before,.rtmedia-container *:after{box-sizing:inherit}.rtmedia-list.rtmedia-list{list-style:none;margin:0;padding:0}.rtmedia-list-item>a{border:0;display:inline-block;text-decoration:none}.rtmedia-list-item>a:focus{outline:0}.rtmedia-list-item>a+p{display:none}.rtmedia-list-item>a .rtmedia-item-thumbnail{width:150px;text-align:center}.rtmedia-list-item>a .rtmedia-item-thumbnail img{display:inline-block;max-height:inherit}#rtmedia-uploader-form .rtm-plupload-list,form .rtmedia-container .rtm-plupload-list,#rtmedia_uploader_filelist{list-style:none;margin-left:-4px;margin-right:-4px;padding-left:0;padding-top:10px}#rtmedia-uploader-form .rtm-plupload-list li,form .rtmedia-container .rtm-plupload-list li,#rtmedia_uploader_filelist li{background:#eee;float:left;margin:4px;max-width:110px;padding:5px;z-index:1;position:relative}#rtmedia-uploader-form .rtm-plupload-list li.upload-error,form .rtmedia-container .rtm-plupload-list li.upload-error,#rtmedia_uploader_filelist li.upload-error{border:1px solid red}#rtmedia-uploader-form .rtm-plupload-list img,form .rtmedia-container .rtm-plupload-list img,#rtmedia_uploader_filelist img{max-width:100%}#rtmedia-uploader-form .rtm-plupload-list canvas,form .rtmedia-container .rtm-plupload-list canvas,#rtmedia_uploader_filelist canvas{display:block;max-width:100%}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-title,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-title,#rtmedia_uploader_filelist .rtm-upload-edit-title{font-size:12px}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-desc,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-desc,#rtmedia_uploader_filelist .rtm-upload-edit-desc{font-size:12px;display:block}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-title-wrapper label,#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-desc-wrapper label,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-title-wrapper label,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-desc-wrapper label,#rtmedia_uploader_filelist .rtm-upload-edit-title-wrapper label,#rtmedia_uploader_filelist .rtm-upload-edit-desc-wrapper label{display:block}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-title-wrapper input.rtm-upload-edit-title,#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-desc-wrapper input.rtm-upload-edit-title,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-title-wrapper input.rtm-upload-edit-title,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-desc-wrapper input.rtm-upload-edit-title,#rtmedia_uploader_filelist .rtm-upload-edit-title-wrapper input.rtm-upload-edit-title,#rtmedia_uploader_filelist .rtm-upload-edit-desc-wrapper input.rtm-upload-edit-title{min-width:100%;margin-top:1px}.rtm-plupload-list:empty{display:none}.rtmedia-uploader-div,.rtmedia-uploader{clear:both}.rtm-upload-button-wrapper button.rtmedia-comment-media-upload,button.rtmedia-comment-media-upload{padding:3px 6px}.rtm-upload-button-wrapper button.rtmedia-comment-media-upload .dashicons,button.rtmedia-comment-media-upload .dashicons{font-size:18px;line-height:20px}button#rtmedia-add-media-button-post-update{padding:3px 6px}button#rtmedia-add-media-button-post-update .dashicons{font-size:18px;line-height:20px}.plupload_file_name{font-size:11px;font-weight:bold;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.plupload_file_size{color:#666;font-size:10px}.plupload_file_action{background:#eee;position:absolute;height:18px;right:4px;top:0;width:18px;z-index:10}.plupload_file_action .dashicons{color:#DD3D36;cursor:pointer;font-size:16px;height:18px;padding:2px 1px;width:18px}.plupload_file_status{height:15px;margin-bottom:5px;overflow:hidden}.plupload_file_progress{background:#7AD03A;height:100%;font-size:10px;line-height:15px;text-align:center;word-wrap:initial}.rtm-form .rtm-field-wrap{margin-bottom:20px}#buddypress a.rtm-button-back{padding:3px 10px}.rtmedia_next_prev{padding:0 10px}.rtm-page-number{float:left}.rtm-page-number .rtm-label{line-height:30px}.rtm-page-number .rtm-label,.rtm-page-number .rtm-go-to-num,.rtm-page-number .rtmedia-page-link{float:left}.rtm-pagination{background:transparent;border:none;color:#888;font-size:small;margin:0;position:relative;display:block;float:left;width:100%;padding:10px 0}.rtm-pagination .rtm-paginate{float:right;font-size:15px}.rtm-pagination .rtm-paginate a,.rtm-pagination .rtm-paginate span{display:inline-block;line-height:1;margin:0 2px;padding:8px;text-decoration:none}.rtm-pagination .rtm-paginate a.rtmedia-page-link{padding:8px}.rtm-pagination .dashicons{font-size:14px;height:auto;line-height:1.2;margin:0;padding:0;width:auto}#rtmedia_go_to_num{font-size:16px;margin:0 5px;padding:4px 5px;width:80px}.rtmedia-upload-not-allowed{background-color:#fcf8e3;border-bottom:1px solid #EEE;color:#c09853;margin-bottom:20px;padding:10px 15px}.plupload_file_name{position:relative}.plupload_file_name .dashicons{background:#eee;color:#DD3D36;cursor:pointer;font-size:14px;height:auto;padding:0 2px 0 5px;position:absolute;right:0;top:0;width:auto}.plupload_file_name .dashicons-yes{color:#7AD03A}.rtmedia-gallery-item-actions{background-color:rgba(0,0,0,0.6);opacity:0;position:absolute;text-align:center;-webkit-transition:all ease-in-out 0.4s;transition:all ease-in-out 0.4s;width:100%;z-index:9}.rtmedia-gallery-item-actions a{border:0;box-shadow:0 0 0;color:#fff;display:inline-block;font-size:12px;outline:none;padding:4px;text-align:left;text-decoration:none;text-transform:uppercase}.rtmedia-gallery-item-actions .dashicons{font-size:17px;margin-right:2px;position:relative;top:1px}.rtmedia-gallery-item-actions .dashicons-trash{font-size:15px}.rtm-pro-allow-action .rtmedia-list-item:hover .rtmedia-gallery-item-actions{opacity:1}.rtm-pro-allow-action .rtmedia-list-item:hover .rtmedia-bulk-edit-item-wrap+.rtmedia-gallery-item-actions{opacity:0}.rtmedia-footer-link{clear:both;overflow:hidden;padding:16px 0;position:relative;text-align:center}.rtmedia-text-link-decoration,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit a,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit span,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete a,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete span,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title a,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title span{text-decoration:none}.rtmedia-text-link-decoration:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit a:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit span:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete a:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete span:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title a:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title span:hover{text-decoration:underline}.rtmedia-container .rtmedia-edit-list-media-table{max-height:300px;overflow-y:auto}.rtmedia-container .rtmedia-edit-list-media-table thead tr{background-color:#50A1D7}.rtmedia-container .rtmedia-edit-list-media-table thead th{text-align:center;color:#FFF}.rtmedia-container .rtmedia-edit-list-media-table tbody tr:nth-child(odd){background:#FFF}.rtmedia-container .rtmedia-edit-list-media-table tbody tr:nth-child(even){background:#DCDCDC}table.rtmedia-edit-media-list tr{line-height:30px}table.rtmedia-edit-media-list tr th{color:#333;padding:4px 10px;line-height:20px}table.rtmedia-edit-media-list tr .rtm-edit-media-list-heading{width:44%}table.rtmedia-edit-media-list tr .rtm-edit-media-list-title-heading{width:56%}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title{padding:4px;font-size:14px;line-height:24px}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title a{text-decoration:none;color:#333}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit{text-align:center}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit a{color:#333;font-size:13px}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete{text-align:center}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete span{color:#FF0000;cursor:pointer;font-size:13px}.rtm-hide{display:none}.rtmedia-list-item .rtmedia-album-media-count{position:absolute;top:0;right:0;background-color:black;color:white;padding:0 5px}.rtmedia-actions-before-description>div{margin-bottom:5px}input.imgedit-submit-btn{display:none}.rtmedia-no-media-found,.rtmedia-list-media{min-height:95px}.privacy_message_wrapper{background:rgba(0,0,0,0.95);z-index:999;color:#fff;display:block;position:fixed;width:100%;padding:5px}.privacy_message_wrapper p{margin:20px 25px;width:-webkit-calc( 100% - 100px );width:calc( 100% - 100px );max-width:100%;font-size:85%;text-align:justify;word-wrap:break-word;display:inline-block}.privacy_message_wrapper p a{color:#fff;text-decoration:underline}.privacy_message_wrapper p a:hover{color:#000}.privacy_message_wrapper #close_rtm_privacy_message{margin:0px;float:right;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);position:absolute;display:inline-block;color:inherit;font-size:25px}.privacy_message_wrapper #close_rtm_privacy_message:hover{cursor:pointer}.hide_privacy_wrapper{display:none}.rtm-tabs.rtm-tabs{border-bottom:1px solid #eee;list-style:none;margin:0 0 20px;padding:0}.rtm-tabs li{border:1px solid #eee;border-bottom:0;float:left;margin:0 5px;padding:0}.rtm-tabs a{border:0;display:block;padding:5px 15px;text-decoration:none}.rtm-tabs a:focus{background:transparent;box-shadow:0 0 0}.rtm-tabs .active{position:relative}.rtm-tabs .active:after{background:#fff;bottom:-1px;content:' ';height:1px;left:0;position:absolute;width:100%}.rtm-tabs .dashicons{font-size:16px;height:auto;line-height:20px;margin-right:8px;width:auto}.rtmedia-edit-media-tabs .rtm-tabs a{border-bottom:0 none}.mfp-bg{top:0;left:0;width:100%;height:100%;z-index:104211;overflow:hidden;position:fixed;background:rgba(0,0,0,0.9)}.mfp-wrap{top:0;left:0;width:100%;height:100%;z-index:104311;position:fixed;outline:none !important;-webkit-backface-visibility:hidden}.mfp-container{text-align:center;position:absolute;width:100%;max-width:84%;margin:0 auto;right:0;height:100%;left:0;top:0;padding:0 8px;box-sizing:border-box}.mfp-container:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.mfp-align-top .mfp-container:before{display:none}.mfp-content{position:relative;display:inline-block;vertical-align:middle;margin:0 auto;text-align:left;z-index:1045}.mfp-inline-holder .mfp-content,.mfp-ajax-holder .mfp-content{width:100%;cursor:auto}.mfp-ajax-cur{cursor:progress}.mfp-zoom-out-cur,.mfp-zoom-out-cur .mfp-image-holder .mfp-close{cursor:zoom-out}.mfp-zoom{cursor:pointer;cursor:zoom-in}.mfp-auto-cursor .mfp-content{cursor:auto}.mfp-close,.mfp-arrow,.mfp-preloader,.mfp-counter{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mfp-loading.mfp-figure{display:none}.mfp-hide{display:none !important}.mfp-s-ready .mfp-preloader{display:none}.mfp-s-error .mfp-content{display:none}button.mfp-close,button.mfp-arrow{overflow:visible;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;display:block;outline:none;padding:0;z-index:1046;box-shadow:none}button::-moz-focus-inner{padding:0;border:0}.mfp-close{background:#fff;color:#999;cursor:pointer;font-size:24px;font-style:normal;height:30px;line-height:30px;padding:0;position:absolute;right:1px;text-align:center;text-decoration:none;text-indent:2px;top:0;width:32px;z-index:12}.mfp-close:hover,.mfp-close:focus{opacity:1;filter:alpha(opacity=100)}.mfp-close:active{top:1px}.mfp-image-holder .mfp-close,.mfp-iframe-holder .mfp-close{color:#FFF;right:-6px;text-align:right;padding-right:6px;width:100%}.mfp-counter{position:absolute;top:0;right:0;color:#CCC;font-size:12px;line-height:18px;white-space:nowrap}.mfp-arrow{cursor:pointer;position:absolute;opacity:0.65;filter:alpha(opacity=65);margin:0;top:50%;margin-top:-55px;padding:0;width:90px;height:110px;-webkit-tap-highlight-color:transparent;opacity:0;z-index:10;-webkit-transition:all 300ms ease-out;transition:all 300ms ease-out}.rtm-single-media:hover .mfp-arrow{opacity:1}@media (max-device-width: 640px){.mfp-arrow{display:none}.rtm-single-media:hover .mfp-arrow{display:none}}.mfp-arrow:active{margin-top:-54px}.mfp-arrow:hover,.mfp-arrow:focus{opacity:1;filter:alpha(opacity=100)}.mfp-arrow:before,.mfp-arrow:after,.mfp-arrow .mfp-b,.mfp-arrow .mfp-a{content:'';display:block;width:0;height:0;position:absolute;left:0;top:0;margin-top:40%;margin-left:40%;border:medium inset transparent}.mfp-arrow:after,.mfp-arrow .mfp-a{border-top-width:13px;border-bottom-width:13px;top:8px}.mfp-arrow:before,.mfp-arrow .mfp-b{border-top-width:21px;border-bottom-width:21px;opacity:0.7}.mfp-arrow-left{left:0}.mfp-arrow-left:after,.mfp-arrow-left .mfp-a{border-right:17px solid #FFF;margin-left:32%}.mfp-arrow-left:before,.mfp-arrow-left .mfp-b{margin-left:25%;border-right:27px solid #3F3F3F}.mfp-arrow-right{right:0}.mfp-arrow-right:after,.mfp-arrow-right .mfp-a{border-left:17px solid #FFF;margin-left:44%}.mfp-arrow-right:before,.mfp-arrow-right .mfp-b{border-left:27px solid #3F3F3F}.mfp-iframe-holder{padding-top:40px;padding-bottom:40px}.mfp-iframe-holder .mfp-content{line-height:0;width:100%;max-width:900px}.mfp-iframe-holder .mfp-close{top:-40px}.mfp-iframe-scaler{width:100%;height:0;overflow:hidden;padding-top:56.25%}.mfp-iframe-scaler iframe{position:absolute;display:block;top:0;left:0;width:100%;height:100%;box-shadow:0 0 8px rgba(0,0,0,0.6);background:#000}img.mfp-img{width:auto;max-width:100%;height:auto;display:block;line-height:0;box-sizing:border-box;padding:40px 0 40px;margin:0 auto}.mfp-figure{line-height:0}.mfp-figure:after{content:'';position:absolute;left:0;top:40px;bottom:40px;display:block;right:0;width:auto;height:auto;z-index:-1;box-shadow:0 0 8px rgba(0,0,0,0.6);background:#444}.mfp-figure small{color:#BDBDBD;display:block;font-size:12px;line-height:14px}.mfp-figure figure{margin:0}.mfp-bottom-bar{margin-top:-36px;position:absolute;top:100%;left:0;width:100%;cursor:auto}.mfp-title{text-align:left;line-height:18px;color:#F3F3F3;word-wrap:break-word;padding-right:36px}.mfp-image-holder .mfp-content{max-width:100%}.mfp-gallery .mfp-image-holder .mfp-figure{cursor:pointer}.mfp-preloader{position:absolute;top:50%;left:0;right:0;margin-top:-36px;z-index:1044;font-size:0;width:36px;height:36px;margin-left:auto;margin-right:auto}.mfp-preloader:before{content:'Loading…';position:absolute;width:30px;height:30px}.mfp-preloader:not(:required):before{content:'';border-radius:50%;border:3px solid rgba(255,255,255,0.27);border-top-color:rgba(255,255,255,0.9);animation:spinner .6s linear infinite;-webkit-animation:spinner .6s linear infinite}@keyframes spinner{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner{to{-webkit-transform:rotate(360deg)}}@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px){.mfp-img-mobile .mfp-image-holder{padding-left:0;padding-right:0}.mfp-img-mobile img.mfp-img{padding:0}.mfp-img-mobile .mfp-figure:after{top:0;bottom:0}.mfp-img-mobile .mfp-figure small{display:inline;margin-left:5px}.mfp-img-mobile .mfp-bottom-bar{background:rgba(0,0,0,0.6);bottom:0;margin:0;top:auto;padding:3px 5px;position:fixed;box-sizing:border-box}.mfp-img-mobile .mfp-bottom-bar:empty{padding:0}.mfp-img-mobile .mfp-counter{right:5px;top:3px}.mfp-img-mobile .mfp-close{top:0;right:0;width:35px;height:35px;line-height:35px;background:rgba(0,0,0,0.6);position:fixed;text-align:center;padding:0}}@media all and (max-width: 900px){.mfp-arrow{-webkit-transform:scale(0.75);-ms-transform:scale(0.75);transform:scale(0.75)}.mfp-arrow-left{-webkit-transform-origin:0;-ms-transform-origin:0;transform-origin:0}.mfp-arrow-right{-webkit-transform-origin:100%;-ms-transform-origin:100%;transform-origin:100%}.mfp-container{padding-left:6px;padding-right:6px}}#atwho-container #atwho-ground-comment_content .atwho-view{z-index:2147483647}.mfp-content .rtm-lightbox-container{background:#000;margin:0 auto;position:relative}.mfp-content .rtm-lightbox-container .rtmedia-comment-media-list .mejs-container.mejs-video{min-height:200px;min-width:200px}.mfp-content .rtm-single-meta{background:#fff;overflow:hidden;padding:20px 20px 110px;position:relative;vertical-align:top}.rtm-single-media{overflow:hidden;position:relative;text-align:center;vertical-align:middle}.rtm-single-media .mejs-container{margin:0 auto;max-width:inherit}.rtm-single-media .rtmedia-message-container{position:absolute;top:45%;left:0;right:0;margin-left:auto;margin-right:auto}@media (max-device-width: 640px){.rtm-single-media .rtmedia-message-container{top:25%}}.rtm-ltb-action-container{background-color:rgba(0,0,0,0.6);bottom:0;color:#fff;line-height:38px;opacity:0;padding:0 10px;position:absolute;width:100%;-webkit-transition:all 300ms ease-out;transition:all 300ms ease-out}.rtm-single-media:hover .rtm-ltb-action-container{opacity:1}@media (max-device-width: 640px){.rtm-ltb-action-container{clear:both;position:relative;opacity:1}.rtm-single-media:hover .rtm-ltb-action-container{opacity:1}}#buddypress #rtmedia-single-media-container.rtmedia-single-media .button{background:transparent;border:0 none;border-radius:2px;color:rgba(255,255,255,0.5);display:block;font-family:inherit;font-weight:normal;line-height:24px;margin:0;padding:0 6px;text-shadow:0 0 0;text-transform:none}#buddypress #rtmedia-single-media-container.rtmedia-single-media .button:hover{background:rgba(255,255,255,0.2);color:rgba(255,255,255,0.8)}#buddypress #rtmedia-single-media-container.rtmedia-single-media .rtm-options .button{color:#333;margin:0 auto;padding:0 4px 0 0}#buddypress #rtm-media-options-list .rtm-options form button{font-size:small}#buddypress #rtm-media-options-list .rtm-options .button{background:transparent;border:0 none;border-radius:2px;color:rgba(255,255,255,0.5);float:left;font-family:inherit;font-weight:normal;line-height:24px;padding:0 6px;text-shadow:0 0 0;text-transform:none}#buddypress #rtm-media-options-list .rtm-options .rtmedia-delete-favlist{color:#fff;padding:0}.rtm-options.rtm-options{background:#666;color:#fff;display:none;font-size:14px;list-style:none;margin:0;padding:8px 10px;position:absolute;left:0;top:38px;width:190px;z-index:10}.rtm-options li{margin:0;overflow:hidden;padding:2px 0}.rtm-media-options .rtm-options:after{bottom:100%;left:20px;border:solid transparent;content:' ';height:0;width:0;position:absolute;pointer-events:none;border-color:rgba(255,255,255,0);border-bottom-color:#666;border-width:6px;margin-left:-6px}.mfp-content .rtm-options{background:#fff;color:#333;bottom:38px;right:0;left:auto;top:auto}.mfp-content .rtm-options:after{top:100%;right:22px;border:solid transparent;content:' ';height:0;width:0;position:absolute;pointer-events:none;border-color:rgba(255,255,255,0);border-top-color:#fff;border-width:6px;margin-left:-6px}.rtm-options .dashicons{font-size:14px;line-height:24px;margin-right:2px}.rtm-media-options .rtm-options a{border:0;color:#fff;display:block;text-decoration:none}.rtm-ltb-title{color:rgba(255,255,255,0.7);float:left;font-size:13px}.rtm-ltb-title a{color:inherit}.rtm-ltb-title a:hover{border-bottom:1px dotted;color:#fff}.rtm-item-actions{float:right}.rtm-item-actions>div,.rtm-item-actions>form{float:left;margin:0 4px 0 0;padding:7px 0;position:relative}.rtmedia-media{margin:0 auto}.rtmedia-media img{display:inline-block;max-height:inherit;height:auto;max-width:100%;width:auto}@media only screen and (max-device-width: 1024px){.rtmedia-media{margin:40px 0}}.rtm-user-meta-details .username{font-size:16px;line-height:1;margin-bottom:6px}.userprofile{float:left;margin:0 16px 16px 0;max-width:54px}.userprofile a{display:block}.userprofile img{height:auto;max-width:100%}.rtm-time-privacy{color:#999;font-size:12px}.rtm-time-privacy .dashicons{font-size:14px;line-height:1.5;margin-top:-2px}.rtmedia-actions-before-comments>span{float:left;margin-right:10px}.rtmedia-actions-before-comments .rtmedia-comment-link,.rtmedia-actions-before-comments .rtmedia-view-conversation,#buddypress .rtmedia-actions-before-comments .rtmedia-like{border:0;font-size:13px;font-weight:normal;line-height:2;padding:0;text-transform:none}.rtmedia-actions-before-comments .rtmedia-comment-link:hover,.rtmedia-actions-before-comments .rtmedia-view-conversation:hover,#buddypress .rtmedia-actions-before-comments .rtmedia-like:hover{background:transparent}.rtmedia-comment-user-pic{float:left;margin-right:10px;max-width:36px}.rtmedia-comment-user-pic img{height:auto;max-width:100%}.rtm-like-comments-info{position:relative}.rtm-like-comments-info:after{bottom:100%;left:15px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none;border-color:rgba(237,239,244,0);border-bottom-color:#edeff4;border-width:4px;margin-left:-4px}.rtm-comment-list.rtm-comment-list{height:340px;list-style:none;margin:0;overflow:auto;padding:0}.rtm-comment-list li{background:#edeff4;font-size:12px;margin-bottom:1px;padding:10px;position:relative}.rtm-comment-list li:hover .rtmedia-delete-comment{opacity:1}.rtm-comment-list .rtmedia-no-comments{margin:0;padding:5px 10px}.rtmedia-like-info{background:#edeff4;font-size:12px;margin-bottom:1px;padding:5px 10px;position:relative}.rtm-comment-wrap{overflow:hidden}.rtm-comment-wrap .rtmedia-comment-author{font-weight:700}.rtm-comment-wrap .rtmedia-comment-date{color:#999;font-size:11px}.rtmedia-comment-content{margin-top:2px}.rtmedia-delete-comment{color:#999;cursor:pointer;font-size:16px;opacity:0;position:absolute;right:5px;top:5px}.rtmedia-comment-content p{margin:0}.rtmedia-comment-details{line-height:1.5;margin-top:-3px}.rt_media_comment_form textarea{display:inline-block;margin-bottom:5px}.rtmedia-item-comments textarea{font-size:14px;padding:4px}.rtm-media-single-comments{bottom:20px;padding:10px;width:100%}.rtm-media-single-comments textarea{background-color:#edeff4;font-size:12px;line-height:14px;max-height:40px;min-height:30px;padding:4px}.rtmedia-popup{background:#fff;margin:20px auto;max-width:600px;padding:20px;position:relative;width:auto}.rtmedia-popup .rtm-modal-title{font-size:24px;margin-bottom:20px;margin-top:0}.rtmedia-popup label{display:block;margin-bottom:5px}#rtm-modal-container p{margin-bottom:10px}#rtm-mejs-video-container{margin:0 auto}.rtmedia-media-name{float:left;max-width:140px;overflow:hidden;text-align:left;text-overflow:ellipsis;white-space:nowrap}.rtm-single-media.rtm-media-type-video{padding-bottom:40px;padding-top:40px}.rtmedia-gallery-alert-container{position:fixed;top:0;left:0;height:100%;width:100%;background-color:rgba(0,0,0,0.6);z-index:999997}.rtmedia-gallery-message-box{position:fixed;top:40%;left:50%;margin-left:auto;margin-right:auto;z-index:999999}.rtmedia-gallery-message-box span{position:relative;left:-50%}#mobile-swipe-overlay{position:absolute;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(255,255,255,0.7);z-index:15;cursor:pointer}#mobile-swipe-overlay .swipe-icon{position:absolute;top:30%;left:50%;font-size:50px;color:#000;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);width:200px}#mobile-swipe-overlay .swipe-icon img{width:100%}#mobile-swipe-overlay .swipe-tootlip{font-weight:800;position:absolute;padding:20px;top:45%;width:100%;text-align:center}.rtmedia-activity-container{box-sizing:border-box}.rtmedia-activity-container *,.rtmedia-activity-container *:before,.rtmedia-activity-container *:after{box-sizing:inherit}.rtmedia-activity-container .rtmedia-list.masonry{list-style:none;padding:0}.rtmedia-activity-container .rtmedia-list.masonry p{display:none}.rtmedia-activity-container .rtmedia-list.masonry:after{content:'';display:block;clear:both}.rtmedia-activity-container .rtmedia-list-item.masonry-brick{display:inline-block;float:left;width:32%;padding:0 !important}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container{min-width:33% !important;margin:0 0 5px 0;width:100% !important}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls{width:100%}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-time-total{display:none}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-horizontal-volume-slider{width:20%;padding-left:5px}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total{width:100%}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-time-loaded{display:none}.rtmedia-activity-container .rtmedia-list-item.masonry-brick img{display:block;max-width:100%}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .rtmedia-item-title{display:none}#buddypress ul.rtmedia-list li{border-bottom:0;padding-bottom:0}.rtmedia-activity-container .rtmedia-item-actions{display:none}.rtmedia-activity-container .rtmedia-item-title,.rtmedia-activity-container .rtmedia-item-title a{border:0;color:#666;font-size:13px;margin:5px 0 0;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}#rtmedia-whts-new-upload-container div{left:0 !important;position:absolute;top:0 !important}#aw-whats-new-submit,.rtmedia-add-media-button{display:block}.rtm-drag-drop-active{border:4px dashed green !important;display:block;height:100%;opacity:0.5;z-index:9999}#rtm-drop-files-title{background:rgba(0,0,0,0.2);display:none;font-size:14px;height:100%;padding:20px;position:absolute;top:0;width:100%}#rtSelectPrivacy{float:right}form.rt_media_comment_form .rtmedia-plupload-container{overflow:hidden}.rtmedia-plupload-container{position:relative;float:left}.rtm-upload-button-wrapper{float:left;margin-right:5px}#rtmedia-action-update{margin-right:10px}.rtmedia-list-item.media-type-photo,.rtmedia-list-item.media-type-document,.rtmedia-list-item.media-type-music,.rtmedia-list-item.media-type-video{display:inline-block}.media-type-music .mejs-container{margin-bottom:10px}.previous-pagination{float:left;margin-top:10px}.next-pagination{float:right;margin-top:10px}@media screen and (max-width: 500px){#activity-stream li .media-type-video{width:100%}#activity-stream li .media-type-video .mejs-video{max-width:100%;min-width:100%}}#rtmedia_show_all_comment{cursor:pointer}#rtmedia_show_all_comment:hover{text-decoration:underline}#whats-new-options{opacity:0;display:none}#whats-new-options .rtmedia-uploader-div{opacity:0;display:none;visibility:hidden}.bp-nouveau .activity-update-form .rtmedia-uploader-div{margin-left:8.5%}.bp-nouveau .activity-update-form .rtmedia-plupload-container{width:25%}.bp-nouveau .activity-update-form .rtmedia-upload-terms #rtmedia_upload_terms_conditions{margin-left:20px}.bp-nouveau .activity-update-form #aw-whats-new-submit{margin-top:15px}.ac-form .rtmedia-uploader-div,.rt_media_comment_form .rtmedia-uploader-div{opacity:1;display:block;visibility:visible}#whats-new-options{opacity:0;display:none}a.rtmedia-comment-link{display:none}a.rtmedia-comment-link.rtmedia-comments-link{display:initial}.rtmedia-album-edit .rtm-checkbox-wrap{background:rgba(255,255,255,0.9);height:30px;line-height:1;padding:10px;position:absolute;z-index:10}.rtmedia-album-edit .rtmedia-item-selector{position:relative;top:-7px}.rtmedia-album-edit .rtmedia-move-container{display:none}.rtm-single-actions.rtm-item-actions{float:none}.rtm-media-type-music .rtmedia-media{width:100%}.media-item .describe{border-collapse:collapse;width:100%;border-top-style:solid;border-top-width:1px;clear:both;cursor:default}.media-item.media-blank .describe{border:0}.media-item .describe th{vertical-align:top;text-align:left;padding:5px 10px 10px;width:140px}.media-item .describe .align th{padding-top:0}.media-item .media-item-info tr{background-color:transparent}.media-item .describe td{padding:0 8px 8px 0;vertical-align:top}.media-item thead.media-item-info td{padding:4px 10px 0}.media-item .media-item-info .A1B1{padding:0 0 0 10px}.media-item td.savesend{padding-bottom:15px}.media-item .thumbnail{max-height:128px;max-width:128px}#wpbody-content #async-upload-wrap a{display:none}.media-upload-form{margin-top:20px}.media-upload-form td label{margin-right:6px;margin-left:2px}.media-upload-form .align .field label{display:inline;padding:0 0 0 23px;margin:0 1em 0 3px;font-weight:bold}.media-upload-form tr.image-size label{margin:0 0 0 5px;font-weight:bold}.media-upload-form th.label label{font-weight:bold;margin:0.5em;font-size:13px}.media-upload-form th.label label span{padding:0 5px}abbr.required{border:medium none;text-decoration:none}.media-item .describe input[type="text"],.media-item .describe textarea{width:460px}.media-item .describe p.help{margin:0;padding:0 0 0 5px}.media-item .edit-attachment,.describe-toggle-on,.describe-toggle-off{display:block;line-height:36px;float:right;margin-right:15px}.media-item .describe-toggle-off,.media-item.open .describe-toggle-on{display:none}.media-item.open .describe-toggle-off{display:block}#media-items .media-item{border-style:solid;border-width:1px;min-height:36px;position:relative;margin-top:-1px;width:100%}#media-items{width:623px}.media-new-php #media-items{margin:1em 0}#media-items:empty{border:0 none}.media-item .filename{line-height:36px;overflow:hidden;padding:0 10px}.media-item .error-div{padding-left:10px}.media-item .pinkynail{float:left;margin:2px 2px 0;max-width:40px;max-height:32px}.media-item .startopen,.media-item .startclosed{display:none}.media-item .original{position:relative;height:34px}.media-item .progress{float:right;height:22px;margin:6px 10px 0 0;width:200px;line-height:2em;padding:0;overflow:hidden;margin-bottom:2px;border:1px solid #d1d1d1;background:#f7f7f7;background-image:-webkit-gradient(linear, left bottom, left top, from(#fff), to(#f7f7f7));background-image:-webkit-linear-gradient(bottom, #fff, #f7f7f7);background-image:linear-gradient(to top, #fff, #f7f7f7);border-radius:3px;box-shadow:inset 0 0 3px rgba(0,0,0,0.1)}.media-item .bar{z-index:9;width:0;height:100%;margin-top:-24px;background-color:#8cc1e9;background-image:-webkit-gradient(linear, left bottom, left top, from(#72a7cf), to(#8cc1e9));background-image:-webkit-linear-gradient(bottom, #72a7cf, #8cc1e9);background-image:linear-gradient(to top, #72a7cf, #8cc1e9);border-radius:3px;box-shadow:0 0 3px rgba(0,0,0,0.3)}.media-item .progress .percent{z-index:10;position:relative;width:200px;padding:0 8px;text-shadow:0 1px 0 rgba(255,255,255,0.4);color:rgba(0,0,0,0.6)}.upload-php .fixed .column-parent{width:15%}.js .html-uploader #plupload-upload-ui{display:none}.js .html-uploader #html-upload-ui{display:block}.media-upload-form .media-item.error{margin:0;padding:0}.media-upload-form .media-item.error p,.media-item .error-div{line-height:16px;margin:5px 10px;padding:0}.media-item .error-div a.dismiss{display:block;float:right;margin:5px 4px 0 15px}.find-box{width:600px;height:300px;overflow:hidden;padding:33px 0 51px;position:absolute;z-index:1000}.find-box-head{cursor:move;font-weight:bold;height:2em;line-height:2em;padding:1px 12px;position:absolute;top:5px;width:100%}.find-box-inside{overflow:auto;padding:6px;height:100%}.find-box-search{overflow:hidden;padding:9px;position:relative}.find-box-search .spinner{float:none;left:125px;position:absolute;top:9px}#find-posts-input{float:left;width:140px;height:24px}#find-posts-search{float:left;margin:1px 4px 0 3px}#find-posts-response{margin:8px 0;padding:0 1px 6px}#find-posts-response table{width:100%}#find-posts-response .found-radio{padding:3px 0 0 8px;width:15px}.find-box-buttons{padding:8px;overflow:hidden}.find-box #resize-se{position:absolute;right:1px;bottom:1px}.ui-find-overlay{position:absolute;top:0;left:0;background-color:#000;opacity:0.6;filter:alpha(opacity=60)}ul#dismissed-updates{display:none}form.upgrade{margin-top:8px}form.upgrade .hint{font-style:italic;font-size:85%;margin:-0.5em 0 2em 0}#poststuff .inside .the-tagcloud{margin:5px 0 10px;padding:8px;border-width:1px;border-style:solid;line-height:1.8em;word-spacing:3px;border-radius:6px}.drag-drop #drag-drop-area{border:4px dashed #DDDDDD;height:200px}.drag-drop .drag-drop-inside{margin:70px auto 0;width:250px}.drag-drop-inside p{color:#aaa;font-size:14px;margin:5px 0;display:none}.drag-drop .drag-drop-inside p{text-align:center}.drag-drop-inside p.drag-drop-info{font-size:20px}.drag-drop .drag-drop-inside p,.drag-drop-inside p.drag-drop-buttons{display:block}.drag-drop.drag-over #drag-drop-area{border-color:#83b4d8}#plupload-upload-ui{position:relative}.describe .image-editor{vertical-align:top}.imgedit-wrap{position:relative}#item-body .imgedit-settings .imgedit-group-top h2{display:inline-block;margin:0}.rtmedia-container .rtmedia-image-editor-cotnainer label{display:inline-block;float:none;margin-right:0}.rtmedia-container .rtmedia-image-editor-cotnainer .dashicons-editor-help{padding:0;height:auto;margin-top:10px}.rtmedia-container .rtmedia-image-editor-cotnainer .hidden{display:none}.imgedit-settings p{margin:8px 0}.post-php .imgedit-wrap table{width:100%}.describe .imgedit-wrap table td,.wp_attachment_holder .imgedit-wrap table td{vertical-align:top;padding-top:0}.describe .imgedit-wrap table td.imgedit-settings{padding:0 5px}.wp_attachment_holder .imgedit-wrap table td.imgedit-settings{width:250px}td.imgedit-settings input{margin-top:0;vertical-align:middle}.imgedit-wait{position:absolute;top:0;background:#fff url(../../../../../../wp-admin/images/wpspin_light.gif) no-repeat scroll 22px 10px;background-size:16px 16px;opacity:0.7;filter:alpha(opacity=70);width:100%;height:500px;display:none}.spinner{background:url(../../../../../../wp-admin/images/wpspin_light.gif) no-repeat;background-size:16px 16px;display:none;float:right;opacity:0.7;filter:alpha(opacity=70);width:16px;height:16px;margin:5px 5px 0}.no-float{float:none}.media-disabled,.imgedit-settings .disabled{color:grey}.wp_attachment_image,.A1B1{overflow:hidden}.wp_attachment_image .button,.A1B1 .button{float:left}.no-js .wp_attachment_image .button{display:none}.wp_attachment_image .spinner,.A1B1 .spinner{float:left;padding:0 4px 4px;vertical-align:bottom}.imgedit-menu{margin:0 0 12px;min-width:300px}.imgedit-menu div{float:left;width:32px;height:32px}.imgedit-crop-wrap{position:relative}.imgedit-crop{margin:0 8px 0 0}.imgedit-crop.disabled:hover{background-position:-9px -31px}.imgedit-crop:hover{background-position:-9px -1px}.imgedit-rleft{margin:0 3px}.imgedit-rleft.disabled:hover{background-position:-46px -31px}.imgedit-rleft:hover{background-position:-46px -1px}.imgedit-rright{margin:0 8px 0 3px}.imgedit-rright.disabled:hover{background-position:-77px -31px}.imgedit-rright:hover{background-position:-77px -1px}.imgedit-flipv{margin:0 3px}.imgedit-flipv.disabled:hover{background-position:-115px -31px}.imgedit-flipv:hover{background-position:-115px -1px}.imgedit-fliph{margin:0 8px 0 3px}.imgedit-fliph.disabled:hover{background-position:-147px -31px}.imgedit-fliph:hover{background-position:-147px -1px}.imgedit-undo{margin:0 3px}.imgedit-undo.disabled:hover{background-position:-184px -31px}.imgedit-undo:hover{background-position:-184px -1px}.imgedit-redo{margin:0 8px 0 3px}.imgedit-redo.disabled:hover{background-position:-215px -31px}.imgedit-redo:hover{background-position:-215px -1px}.imgedit-applyto img{margin:0 8px 0 0}.imgedit-group h3{font-size:18px}.imgedit-group .dashicons{border:0;line-height:1.2}.imgedit-group-top{margin:5px 0}.imgedit-applyto .imgedit-label{padding:2px 0 0;display:block}.imgedit-help{display:none;font-style:italic;margin-bottom:8px}a.imgedit-help-toggle{text-decoration:none}.form-table td.imgedit-response{padding:0}.imgedit-submit{margin:8px 0}.imgedit-submit-btn{margin-left:20px}.imgedit-wrap .nowrap{white-space:nowrap}span.imgedit-scale-warn{color:red;font-size:20px;font-style:normal;visibility:hidden;vertical-align:middle}.wp_attachment_details{margin-bottom:20px}.imgedit-menu div{border-color:#d5d5d5;background-color:#f1f1f1}.imgedit-menu div:hover{border-color:#c1c1c1;background-color:#eaeaea}.imgedit-menu div.disabled{border-color:#ccc;background-color:#ddd;filter:alpha(opacity=50);opacity:0.5}.bp-media-image-editor-cotnainer{margin-top:35px}.wp_attachment_image .bp-media-image-edit{float:left}.wp_attachment_image .spinner{display:none}.bp-media-image-editor-cotnainer .hidden{display:none}.bp-media-image-editor-cotnainer div.updated{margin:5px 0 15px;background-color:#ffffe0;border-color:#e6db55;padding:0 .6em;border-radius:3px;border-width:1px;border-style:solid}.bp-media-image-editor-cotnainer div.updated p{margin:.5em 0;padding:2px}body article.bp_members.bp_member .entry-content,body div.bp_members.bp_member .entry-content{width:100%}.rtm-media-gallery-uploader{display:none}.rtmedia-uploader .drag-drop{border:4px dashed #DDD;text-align:center;background:#fafafa;overflow:hidden;color:#AAAAAA;margin-top:20px;padding:25px 0}.rtmedia-uploader .drag-drop.dragover{border-color:#83b4d8}.rtmedia-uploader .drag-drop .drag-drop-info{font-size:20px;line-height:24px}.rtmedia-uploader .drag-drop .rtm-select-files span{vertical-align:middle}.rtmedia-uploader .drag-drop .rtm-seperator{margin:0px 20px}.rtmedia-uploader .drag-drop .start-media-upload{display:none;margin-top:20px}.rtmedia-uploader .drag-drop .rtm-file-size-limit{vertical-align:middle;font-size:16px;line-height:24px}.rtm-uploader-main-wrapper .rtm-uploader-tabs{margin-bottom:10px;text-align:left}.rtm-uploader-main-wrapper ul{border-bottom:1px solid #CCC}.rtm-uploader-main-wrapper li{margin:0 0 -1px 10px;display:inline-block;padding:5px 10px;line-height:25px;background-color:#e4e4e4;border:1px solid #CCC}.rtm-uploader-main-wrapper li.active{background:transparent;border-left:1px solid #CCC;border-top:1px solid #CCC;border-right:1px solid #CCC;border-bottom:1px solid #fafafa}.rtm-uploader-main-wrapper li:hover{cursor:pointer}.rtmedia-container .rtmedia-list{margin:10px -5px}.rtmedia-container .rtmedia-list .rtmedia-list-item{float:left;margin:5px;position:relative}.rtmedia-container .rtmedia-list .rtmedia-list-item>a{display:block}.rtmedia-container .rtmedia-list .rtmedia_time{background-color:#000;color:#fff;display:inline-block;font-size:11px;font-weight:bold;line-height:14px;opacity:0.75;padding:0 4px;position:absolute;right:2px;top:2px}.rtmedia-container .rtmedia-list img{vertical-align:top}.rtmedia-container .rtmedia-list .rtmedia-item-title h4{color:#666;font-size:12px;font-weight:normal;margin:5px 0 0;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}.rtm-load-more{background:#eee;text-align:center}.rtmedia-container .rtm-load-more a{border:0;padding:10px 0}.rtm-load-more .rtm-media-loading{padding:10px 0}.rtm-media-options.rtm-media-search-enable>*:nth-last-child(2){border-right:none}.rtm-media-options{line-height:1.4;margin-bottom:10px;clear:both}.rtm-media-options>div{display:inline-block;cursor:pointer}.rtm-media-options .rtm-media-options-list{margin-right:5px;padding-right:10px;position:relative}.rtm-media-options>*{border-right:1px solid #999}.rtm-media-options>*:last-child{border-right:none}.rtm-media-options .dashicons{font-size:inherit;line-height:1.4}#buddypress .media_search.media_search .search_by{margin-top:3px}.bp-legacy.media #buddypress #item-header-cover-image .user-nicename{margin-bottom:20px}.bp-legacy.media #buddypress div#item-header div#item-header-content ul li,.bp-legacy.media #buddypress div#item-header div#item-header-content ul div{float:left;margin:2px 10px}.bp-legacy.media #buddypress div#item-header div#item-header-content button,.bp-legacy.media #buddypress div#item-header div#item-header-content a{background:#fff;border:1px solid #ccc;color:#767676;font-size:small;cursor:pointer;outline:none;padding:4px 10px;text-align:center;text-decoration:none}.bp-legacy.media #buddypress div#item-header div#item-header-content button:hover,.bp-legacy.media #buddypress div#item-header div#item-header-content a:hover{background:#ededed;border:1px solid #bbb;color:#555;outline:none}.bp-nouveau.media .entry-title{font-size:34px;font-weight:inherit;margin-bottom:0}.bp-nouveau.media .entry-title a{color:#767676}.bp-nouveau.media #buddypress #item-header-cover-image .user-nicename{margin-top:15px;margin-bottom:30px}.bp-nouveau.media #buddypress div#item-header div#item-header-content ul li,.bp-nouveau.media #buddypress div#item-header div#item-header-content ul div{float:left;margin:2px 10px}.bp-nouveau.media #buddypress div#item-header div#item-header-content button,.bp-nouveau.media #buddypress div#item-header div#item-header-content a{background:#fff;border-color:#ccc;border-style:solid;border-width:1px;color:#555;cursor:pointer;font-size:inherit;font-weight:400;outline:none;padding:0.3em 0.5em;text-align:center;text-decoration:none;width:auto}.bp-nouveau.media #buddypress div#item-header div#item-header-content button:hover,.bp-nouveau.media #buddypress div#item-header div#item-header-content a:hover{background:#ededed;border-color:#999999;color:#333;outline:none;text-decoration:none}.media_search.media_search{float:right;border:1px solid #ccc;margin-left:5px;padding:3px 0}.media_search.media_search .media_search_input{width:200px;outline:0;max-width:200px;margin:0;box-shadow:none;padding:5px 6px;border:none;background:transparent;float:left;max-height:30px}.media_search.media_search #media_fatch_loader.load{float:left;width:20px;height:30px;position:relative}.media_search.media_search #media_fatch_loader.load:before{content:'';border-radius:50%;border:1px solid #aaa;border-top-color:rgba(255,255,255,0.9);animation:spinner .8s linear infinite;-webkit-animation:spinner .8s linear infinite;position:absolute;width:15px;height:15px;top:24%}.media_search.media_search .search_option{padding:0;background:transparent;color:#000;margin-bottom:0;line-height:1;border:none}.media_search.media_search .media_search_remove.search_option{display:none}.media_search.media_search .media_search_remove.search_option i{margin-top:4px}.media_search.media_search .search_by{background:transparent;margin-top:3px;float:left;width:auto;margin-bottom:0;height:auto;padding-top:0;padding-bottom:0}@keyframes spinner{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner{to{-webkit-transform:rotate(360deg)}}.rtmedia-upload-media-link{cursor:pointer}a.rtmedia-upload-media-link{border:none}.rtm-album-privacy span{font-size:16px;display:inline-block;margin:0 20px 20px 20px;vertical-align:top}.rtm-album-privacy label{margin-right:8px}.rtm-album-privacy .dashicons{font-size:16px;line-height:1.6;margin-right:5px}#rtm-media-options-list .rtmedia-delete-album{background:transparent;border:0;color:#fff;font-family:inherit;font-size:inherit;font-weight:inherit;padding:0;text-transform:inherit}#rtm-media-options-list .rtmedia-delete-album:hover{background:transparent;border:0;color:#fff}.rtmedia-single-container button.rtmedia-like{background-color:transparent;color:inherit}#buddypress #item-body{padding:0 20px}#buddypress .mejs-controls button{padding:4px 8px;border:none;background:transparent url("../../../lib/media-element/mejs-controls.png") no-repeat}#buddypress .mejs-controls .mejs-play>button{background-position:0 0}#buddypress .mejs-controls .mejs-pause>button{background-position:-20px 0}#buddypress .mejs-controls .mejs-unmute>button{background-position:-40px 0}#buddypress .mejs-controls .mejs-mute>button{background-position:-60px 0}#buddypress .mejs-controls .mejs-fullscreen-button>button{background-position:-80px 0}#buddypress .mejs-controls .mejs-unfullscreen>button{background-position:-100px 0}#buddypress .mejs-controls .mejs-replay>button{background-position:-160px 0}.mejs-container .mejs-controls .mejs-time{padding:15px 3px 0;content:''}.rtmedia-activity-container .mejs-playpause-button.mejs-play button:before,.rtmedia-activity-container .mejs-playpause-button.mejs-pause button:before,.rtmedia-activity-container .mejs-volume-button.mejs-mute button:before,.rtmedia-activity-container .mejs-fullscreen-button button:before,.rtmedia-media .mejs-playpause-button.mejs-play button:before,.rtmedia-media .mejs-playpause-button.mejs-pause button:before,.rtmedia-media .mejs-volume-button.mejs-mute button:before,.rtmedia-media .mejs-fullscreen-button button:before{content:''}@media only screen and (min-width: 1025px){.mfp-content .rtm-lightbox-container{display:-webkit-box;display:-ms-flexbox;display:flex;table-layout:fixed;width:100%;min-height:473px}.mfp-content .rtm-mfp-close{background:transparent}.mfp-content .rtm-single-media{display:-webkit-box;display:-ms-flexbox;display:flex;width:66.6667%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.mfp-content .rtm-single-meta{display:block;width:33.3333%;padding:20px}.mfp-content .rtm-single-meta .rtmedia-scroll{height:100%;overflow-X:hidden}}.rtl #rtSelectPrivacy{float:left}.rtl .rtmedia-plupload-container{float:right}.rtl .rtm-upload-button-wrapper{float:right}.rtl #whats-new-post-in-box{float:right}.rtl .describe-toggle-off{float:left}.rtl .media-item .pinkynail{float:right}.rtl .media-item .progress{float:left}.rtl .media-item .error-div a.dismiss{float:left}.rtl #find-posts-input{float:right}.rtl #find-posts-search{float:right}.rtl .spinner{float:left}.rtl .wp_attachment_image .button,.rtl .A1B1 .button{float:right}.rtl .wp_attachment_image .spinner,.rtl .A1B1 .spinner{float:right}.rtl .imgedit-menu div{float:right}.rtl .wp_attachment_image .bp-media-image-edit{float:right}.rtl .rtmedia-container .rtmedia-list .rtmedia-list-item{float:right}.rtl #buddypress #rtm-media-options-list .rtm-options .button{float:right}.rtl .rtm-ltb-title{float:right}.rtl .rtm-item-actions{float:left}.rtl .rtm-item-actions>div,.rtl .rtm-item-actions>form{float:right}.rtl .userprofile{float:right}.rtl .rtmedia-actions-before-comments>span{float:right}.rtl .rtmedia-comment-user-pic{float:right}.rtl .rtmedia-media-name{float:right}.rtl #rtmedia-uploader-form .rtm-plupload-list li,.rtl #rtmedia_uploader_filelist li{float:right}.rtl .rtm-page-number{float:right}.rtl .rtm-page-number .rtmedia-page-link{float:right}.rtl .rtm-pagination{float:right}.rtl .rtm-pagination .rtm-paginate{float:left}.rtl .rtm-tabs li{float:right}.rtl .alignleft{float:right}.rtl .alignright{float:left}
1
+ .alignleft{float:left}.alignright{float:right}.aligncenter{display:block;margin-left:auto;margin-right:auto;text-align:center}.clear-both{clear:both}.clear-none{clear:none}.clear-left{clear:left}.clear-right{clear:right}.rtm-inline-block{display:inline-block}.rtm-text-left{text-align:left}.rtm-text-right{text-align:right}.rtm-text-center{text-align:center}.rtm-border-0{border:0 !important}.hide{display:none}.rtmedia-success,.rtmedia-warning{margin:10px 0;padding:8px 14px 8px 14px;text-shadow:0 1px 0 rgba(255,255,255,0.5);border-bottom:1px solid #e7e7e7;cursor:pointer}.rtmedia-success{background-color:#dff0d8;color:#468847}.rtmedia-warning{background-color:#F0D8DD;color:#884646}.clearfix:after{content:"";display:table;clear:both}#buddypress form#whats-new-form textarea{box-sizing:border-box;min-height:70px;width:100%}#buddypress #whats-new-form .rtmedia-uploader-div{display:none}#buddypress #whats-new-form #whats-new-options .rtmedia-uploader-div{display:block}#buddypress #whats-new-options{height:auto !important;overflow:hidden}#buddypress form#whats-new-form p.activity-greeting{line-height:1}#buddypress form#whats-new-form #whats-new-options select{border:1px solid #ccc;font-size:13px;margin-top:0;padding:3px 2px}#whats-new-submit #aw-whats-new-submit{font-size:12px;line-height:18px;padding:4px 6px}#whats-new-post-in-box{float:left;font-size:13px}#buddypress form#whats-new-form #whats-new-submit{margin-top:0}#whats-new-textarea{margin-bottom:10px}body.media.buddypress{overflow-y:auto}#buddypress input[type=submit]:focus{background:#ededed;border:1px solid #bbb;color:#555;outline:0;text-decoration:none}#buddypress ul.activity-list li.activity-item .activity-comments .rtmedia-uploader-div{color:#767676;margin-left:50px;padding-left:15px}#buddypress form#whats-new-form #whats-new-content.active #whats-new-options[style] #whats-new-post-in-box{margin-top:0}#whats-new-post-in-box{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.rtmedia-container{box-sizing:border-box}.rtmedia-container *,.rtmedia-container *:before,.rtmedia-container *:after{box-sizing:inherit}.rtmedia-list.rtmedia-list{list-style:none;margin:0;padding:0}.rtmedia-list-item>a{border:0;display:inline-block;text-decoration:none}.rtmedia-list-item>a:focus{outline:0}.rtmedia-list-item>a+p{display:none}.rtmedia-list-item>a .rtmedia-item-thumbnail{width:150px;text-align:center}.rtmedia-list-item>a .rtmedia-item-thumbnail img{display:inline-block;max-height:inherit}#rtmedia-uploader-form .rtm-plupload-list,form .rtmedia-container .rtm-plupload-list,#rtmedia_uploader_filelist{list-style:none;margin-left:-4px;margin-right:-4px;padding-left:0;padding-top:10px}#rtmedia-uploader-form .rtm-plupload-list li,form .rtmedia-container .rtm-plupload-list li,#rtmedia_uploader_filelist li{background:#eee;float:left;margin:4px;max-width:110px;padding:5px;z-index:1;position:relative}#rtmedia-uploader-form .rtm-plupload-list li.upload-error,form .rtmedia-container .rtm-plupload-list li.upload-error,#rtmedia_uploader_filelist li.upload-error{border:1px solid red}#rtmedia-uploader-form .rtm-plupload-list img,form .rtmedia-container .rtm-plupload-list img,#rtmedia_uploader_filelist img{max-width:100%}#rtmedia-uploader-form .rtm-plupload-list canvas,form .rtmedia-container .rtm-plupload-list canvas,#rtmedia_uploader_filelist canvas{display:block;max-width:100%}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-title,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-title,#rtmedia_uploader_filelist .rtm-upload-edit-title{font-size:12px}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-desc,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-desc,#rtmedia_uploader_filelist .rtm-upload-edit-desc{font-size:12px;display:block}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-title-wrapper label,#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-desc-wrapper label,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-title-wrapper label,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-desc-wrapper label,#rtmedia_uploader_filelist .rtm-upload-edit-title-wrapper label,#rtmedia_uploader_filelist .rtm-upload-edit-desc-wrapper label{display:block}#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-title-wrapper input.rtm-upload-edit-title,#rtmedia-uploader-form .rtm-plupload-list .rtm-upload-edit-desc-wrapper input.rtm-upload-edit-title,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-title-wrapper input.rtm-upload-edit-title,form .rtmedia-container .rtm-plupload-list .rtm-upload-edit-desc-wrapper input.rtm-upload-edit-title,#rtmedia_uploader_filelist .rtm-upload-edit-title-wrapper input.rtm-upload-edit-title,#rtmedia_uploader_filelist .rtm-upload-edit-desc-wrapper input.rtm-upload-edit-title{min-width:100%;margin-top:1px}.rtm-plupload-list:empty{display:none}.rtmedia-uploader-div,.rtmedia-uploader{clear:both}.rtm-upload-button-wrapper button.rtmedia-comment-media-upload,button.rtmedia-comment-media-upload{padding:3px 6px}.rtm-upload-button-wrapper button.rtmedia-comment-media-upload .dashicons,button.rtmedia-comment-media-upload .dashicons{font-size:18px;line-height:20px}button#rtmedia-add-media-button-post-update{padding:3px 6px}button#rtmedia-add-media-button-post-update .dashicons{font-size:18px;line-height:20px}.plupload_file_name{font-size:11px;font-weight:bold;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.plupload_file_size{color:#666;font-size:10px}.plupload_file_action{background:#eee;position:absolute;height:18px;right:4px;top:0;width:18px;z-index:10}.plupload_file_action .dashicons{color:#DD3D36;cursor:pointer;font-size:16px;height:18px;padding:2px 1px;width:18px}.plupload_file_status{height:15px;margin-bottom:5px;overflow:hidden}.plupload_file_progress{background:#7AD03A;height:100%;font-size:10px;line-height:15px;text-align:center;word-wrap:initial}.rtm-form .rtm-field-wrap{margin-bottom:20px}#buddypress a.rtm-button-back{padding:3px 10px}#buddypress div.rtmedia-page-no.rtm-page-number a.rtmedia-page-link.button{padding:5px 10px}.rtmedia_next_prev{padding:0 10px}.rtm-page-number{float:left}.rtm-page-number .rtm-label{line-height:30px}.rtm-page-number .rtm-label,.rtm-page-number .rtm-go-to-num,.rtm-page-number .rtmedia-page-link{float:left}.rtm-page-number .rtm-go-to-num,.rtm-page-number .rtmedia-page-link{line-height:1.5}.rtm-pagination{background:transparent;border:none;color:#888;font-size:small;margin:0;position:relative;display:block;float:left;width:100%;padding:10px 0}.rtm-pagination .rtm-paginate{float:right;font-size:15px}.rtm-pagination .rtm-paginate a,.rtm-pagination .rtm-paginate span{display:inline-block;line-height:1;margin:0 2px;padding:8px;text-decoration:none}.rtm-pagination .rtm-paginate a.rtmedia-page-link{padding:8px}.rtm-pagination .dashicons{font-size:14px;height:auto;line-height:1.2;margin:0;padding:0;width:auto}#rtmedia_go_to_num{font-size:16px;margin:0 5px;padding:3px 5px;width:80px}.rtmedia-upload-not-allowed{background-color:#fcf8e3;border-bottom:1px solid #EEE;color:#c09853;margin-bottom:20px;padding:10px 15px}.plupload_file_name{position:relative}.plupload_file_name .dashicons{background:#eee;color:#DD3D36;cursor:pointer;font-size:14px;height:auto;padding:0 2px 0 5px;position:absolute;right:0;top:0;width:auto}.plupload_file_name .dashicons-yes{color:#7AD03A}.rtmedia-gallery-item-actions{background-color:rgba(0,0,0,0.6);opacity:0;position:absolute;text-align:center;-webkit-transition:all ease-in-out 0.4s;transition:all ease-in-out 0.4s;width:100%;z-index:9}.rtmedia-gallery-item-actions a{border:0;box-shadow:0 0 0;color:#fff;display:inline-block;font-size:12px;outline:none;padding:4px;text-align:left;text-decoration:none;text-transform:uppercase}.rtmedia-gallery-item-actions .dashicons{font-size:17px;margin-right:2px;position:relative;top:1px}.rtmedia-gallery-item-actions .dashicons-trash{font-size:15px}.rtm-pro-allow-action .rtmedia-list-item:hover .rtmedia-gallery-item-actions{opacity:1}.rtm-pro-allow-action .rtmedia-list-item:hover .rtmedia-bulk-edit-item-wrap+.rtmedia-gallery-item-actions{opacity:0}.rtmedia-footer-link{clear:both;overflow:hidden;padding:16px 0;position:relative;text-align:center}.rtmedia-text-link-decoration,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit a,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit span,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete a,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete span,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title a,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title span{text-decoration:none}.rtmedia-text-link-decoration:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit a:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit span:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete a:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete span:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title a:hover,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title span:hover{text-decoration:underline}.rtmedia-container .rtmedia-edit-list-media-table{max-height:300px;overflow-y:auto}.rtmedia-container .rtmedia-edit-list-media-table thead tr{background-color:#50A1D7}.rtmedia-container .rtmedia-edit-list-media-table thead th{text-align:center;color:#FFF}.rtmedia-container .rtmedia-edit-list-media-table tbody tr:nth-child(odd){background:#FFF}.rtmedia-container .rtmedia-edit-list-media-table tbody tr:nth-child(even){background:#DCDCDC}table.rtmedia-edit-media-list tr{line-height:30px}table.rtmedia-edit-media-list tr th{color:#333;padding:4px 10px;line-height:20px}table.rtmedia-edit-media-list tr .rtm-edit-media-list-heading{width:44%}table.rtmedia-edit-media-list tr .rtm-edit-media-list-title-heading{width:56%}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete,table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title{padding:4px;font-size:14px;line-height:24px}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-title a{text-decoration:none;color:#333}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit{text-align:center}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-edit a{color:#333;font-size:13px}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete{text-align:center}table.rtmedia-edit-media-list tr td.rtm-edit-media-list-delete span{color:#FF0000;cursor:pointer;font-size:13px}.rtm-hide{display:none}.rtmedia-list-item .rtmedia-album-media-count{position:absolute;top:0;right:0;background-color:black;color:white;padding:0 5px}.rtmedia-actions-before-description>div{margin-bottom:5px}input.imgedit-submit-btn{display:none}.rtmedia-no-media-found,.rtmedia-list-media{min-height:95px}.privacy_message_wrapper{background:rgba(0,0,0,0.95);z-index:999;color:#fff;display:block;position:fixed;width:100%;padding:5px}.privacy_message_wrapper p{margin:20px 25px;width:-webkit-calc( 100% - 100px );width:calc( 100% - 100px );max-width:100%;font-size:85%;text-align:justify;word-wrap:break-word;display:inline-block}.privacy_message_wrapper p a{color:#fff;text-decoration:underline}.privacy_message_wrapper p a:hover{color:#000}.privacy_message_wrapper #close_rtm_privacy_message{margin:0px;float:right;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);position:absolute;display:inline-block;color:inherit;font-size:25px}.privacy_message_wrapper #close_rtm_privacy_message:hover{cursor:pointer}.hide_privacy_wrapper{display:none}.rtm-tabs.rtm-tabs{border-bottom:1px solid #eee;list-style:none;margin:0 0 20px;padding:0}.rtm-tabs li{border:1px solid #eee;border-bottom:0;float:left;margin:0 5px;padding:0}.rtm-tabs a{border:0;display:block;padding:5px 15px;text-decoration:none}.rtm-tabs a:focus{background:transparent;box-shadow:0 0 0}.rtm-tabs .active{position:relative}.rtm-tabs .active:after{background:#fff;bottom:-1px;content:' ';height:1px;left:0;position:absolute;width:100%}.rtm-tabs .dashicons{font-size:16px;height:auto;line-height:20px;margin-right:8px;width:auto}.rtmedia-edit-media-tabs .rtm-tabs a{border-bottom:0 none}.mfp-bg{top:0;left:0;width:100%;height:100%;z-index:104211;overflow:hidden;position:fixed;background:rgba(0,0,0,0.9)}.mfp-wrap{top:0;left:0;width:100%;height:100%;z-index:104311;position:fixed;outline:none !important;-webkit-backface-visibility:hidden}.mfp-container{text-align:center;position:absolute;width:100%;max-width:84%;margin:0 auto;right:0;height:100%;left:0;top:0;padding:0 8px;box-sizing:border-box}.mfp-container:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.mfp-align-top .mfp-container:before{display:none}.mfp-content{position:relative;display:inline-block;vertical-align:middle;margin:0 auto;text-align:left;z-index:1045}.mfp-inline-holder .mfp-content,.mfp-ajax-holder .mfp-content{width:100%;cursor:auto}.mfp-ajax-cur{cursor:progress}.mfp-zoom-out-cur,.mfp-zoom-out-cur .mfp-image-holder .mfp-close{cursor:zoom-out}.mfp-zoom{cursor:pointer;cursor:zoom-in}.mfp-auto-cursor .mfp-content{cursor:auto}.mfp-close,.mfp-arrow,.mfp-preloader,.mfp-counter{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mfp-loading.mfp-figure{display:none}.mfp-hide{display:none !important}.mfp-s-ready .mfp-preloader{display:none}.mfp-s-error .mfp-content{display:none}button.mfp-close,button.mfp-arrow{overflow:visible;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;display:block;outline:none;padding:0;z-index:1046;box-shadow:none}button::-moz-focus-inner{padding:0;border:0}.mfp-close{background:#fff;color:#999;cursor:pointer;font-size:24px;font-style:normal;height:30px;line-height:30px;padding:0;position:absolute;right:1px;text-align:center;text-decoration:none;text-indent:2px;top:0;width:32px;z-index:12}.mfp-close:hover,.mfp-close:focus{opacity:1;filter:alpha(opacity=100)}.mfp-close:active{top:1px}.mfp-image-holder .mfp-close,.mfp-iframe-holder .mfp-close{color:#FFF;right:-6px;text-align:right;padding-right:6px;width:100%}.mfp-counter{position:absolute;top:0;right:0;color:#CCC;font-size:12px;line-height:18px;white-space:nowrap}.mfp-arrow{cursor:pointer;position:absolute;opacity:0.65;filter:alpha(opacity=65);margin:0;top:50%;margin-top:-55px;padding:0;width:90px;height:110px;-webkit-tap-highlight-color:transparent;opacity:0;z-index:10;-webkit-transition:all 300ms ease-out;transition:all 300ms ease-out}.rtm-single-media:hover .mfp-arrow{opacity:1}@media (max-device-width: 640px){.mfp-arrow{display:none}.rtm-single-media:hover .mfp-arrow{display:none}}.mfp-arrow:active{margin-top:-54px}.mfp-arrow:hover,.mfp-arrow:focus{opacity:1;filter:alpha(opacity=100)}.mfp-arrow:before,.mfp-arrow:after,.mfp-arrow .mfp-b,.mfp-arrow .mfp-a{content:'';display:block;width:0;height:0;position:absolute;left:0;top:0;margin-top:40%;margin-left:40%;border:medium inset transparent}.mfp-arrow:after,.mfp-arrow .mfp-a{border-top-width:13px;border-bottom-width:13px;top:8px}.mfp-arrow:before,.mfp-arrow .mfp-b{border-top-width:21px;border-bottom-width:21px;opacity:0.7}.mfp-arrow-left{left:0}.mfp-arrow-left:after,.mfp-arrow-left .mfp-a{border-right:17px solid #FFF;margin-left:32%}.mfp-arrow-left:before,.mfp-arrow-left .mfp-b{margin-left:25%;border-right:27px solid #3F3F3F}.mfp-arrow-right{right:0}.mfp-arrow-right:after,.mfp-arrow-right .mfp-a{border-left:17px solid #FFF;margin-left:44%}.mfp-arrow-right:before,.mfp-arrow-right .mfp-b{border-left:27px solid #3F3F3F}.mfp-iframe-holder{padding-top:40px;padding-bottom:40px}.mfp-iframe-holder .mfp-content{line-height:0;width:100%;max-width:900px}.mfp-iframe-holder .mfp-close{top:-40px}.mfp-iframe-scaler{width:100%;height:0;overflow:hidden;padding-top:56.25%}.mfp-iframe-scaler iframe{position:absolute;display:block;top:0;left:0;width:100%;height:100%;box-shadow:0 0 8px rgba(0,0,0,0.6);background:#000}img.mfp-img{width:auto;max-width:100%;height:auto;display:block;line-height:0;box-sizing:border-box;padding:40px 0 40px;margin:0 auto}.mfp-figure{line-height:0}.mfp-figure:after{content:'';position:absolute;left:0;top:40px;bottom:40px;display:block;right:0;width:auto;height:auto;z-index:-1;box-shadow:0 0 8px rgba(0,0,0,0.6);background:#444}.mfp-figure small{color:#BDBDBD;display:block;font-size:12px;line-height:14px}.mfp-figure figure{margin:0}.mfp-bottom-bar{margin-top:-36px;position:absolute;top:100%;left:0;width:100%;cursor:auto}.mfp-title{text-align:left;line-height:18px;color:#F3F3F3;word-wrap:break-word;padding-right:36px}.mfp-image-holder .mfp-content{max-width:100%}.mfp-gallery .mfp-image-holder .mfp-figure{cursor:pointer}.mfp-preloader{position:absolute;top:50%;left:0;right:0;margin-top:-36px;z-index:1044;font-size:0;width:36px;height:36px;margin-left:auto;margin-right:auto}.mfp-preloader:before{content:'Loading…';position:absolute;width:30px;height:30px}.mfp-preloader:not(:required):before{content:'';border-radius:50%;border:3px solid rgba(255,255,255,0.27);border-top-color:rgba(255,255,255,0.9);animation:spinner .6s linear infinite;-webkit-animation:spinner .6s linear infinite}@keyframes spinner{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner{to{-webkit-transform:rotate(360deg)}}@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px){.mfp-img-mobile .mfp-image-holder{padding-left:0;padding-right:0}.mfp-img-mobile img.mfp-img{padding:0}.mfp-img-mobile .mfp-figure:after{top:0;bottom:0}.mfp-img-mobile .mfp-figure small{display:inline;margin-left:5px}.mfp-img-mobile .mfp-bottom-bar{background:rgba(0,0,0,0.6);bottom:0;margin:0;top:auto;padding:3px 5px;position:fixed;box-sizing:border-box}.mfp-img-mobile .mfp-bottom-bar:empty{padding:0}.mfp-img-mobile .mfp-counter{right:5px;top:3px}.mfp-img-mobile .mfp-close{top:0;right:0;width:35px;height:35px;line-height:35px;background:rgba(0,0,0,0.6);position:fixed;text-align:center;padding:0}}@media all and (max-width: 900px){.mfp-arrow{-webkit-transform:scale(0.75);-ms-transform:scale(0.75);transform:scale(0.75)}.mfp-arrow-left{-webkit-transform-origin:0;-ms-transform-origin:0;transform-origin:0}.mfp-arrow-right{-webkit-transform-origin:100%;-ms-transform-origin:100%;transform-origin:100%}.mfp-container{padding-left:6px;padding-right:6px}}.atwho-container #atwho-ground-comment_content .atwho-view{z-index:2147483647}.mfp-content .rtm-lightbox-container{background:#000;margin:0 auto;position:relative}.mfp-content .rtm-lightbox-container .rtmedia-comment-media-list .mejs-container.mejs-video{min-height:200px;min-width:200px}.mfp-content .rtm-single-meta{background:#fff;overflow:hidden;padding:20px 20px 110px;position:relative;vertical-align:top}.rtm-single-media{overflow:hidden;position:relative;text-align:center;vertical-align:middle}.rtm-single-media .mejs-container{margin:0 auto;max-width:inherit}.rtm-single-media .rtmedia-message-container{position:absolute;top:45%;left:0;right:0;margin-left:auto;margin-right:auto}@media (max-device-width: 640px){.rtm-single-media .rtmedia-message-container{top:25%}}.rtm-ltb-action-container{background-color:rgba(0,0,0,0.6);bottom:0;color:#fff;line-height:38px;opacity:0;padding:0 10px;position:absolute;width:100%;-webkit-transition:all 300ms ease-out;transition:all 300ms ease-out}.rtm-single-media:hover .rtm-ltb-action-container{opacity:1}@media (max-device-width: 640px){.rtm-ltb-action-container{clear:both;position:relative;opacity:1}.rtm-single-media:hover .rtm-ltb-action-container{opacity:1}}#buddypress #rtmedia-single-media-container.rtmedia-single-media .button{background:transparent;border:0 none;border-radius:2px;color:rgba(255,255,255,0.5);display:block;font-family:inherit;font-weight:normal;line-height:24px;margin:0;padding:0 6px;text-shadow:0 0 0;text-transform:none}#buddypress #rtmedia-single-media-container.rtmedia-single-media .button:hover{background:rgba(255,255,255,0.2);color:rgba(255,255,255,0.8)}#buddypress #rtmedia-single-media-container.rtmedia-single-media .rtm-options .button{color:#333;margin:0 auto;padding:0 4px 0 0}#buddypress #rtm-media-options-list .rtm-options .button{background:transparent;border:0 none;border-radius:2px;color:rgba(255,255,255,0.5);float:left;font-family:inherit;font-weight:normal;line-height:24px;padding:0 6px;text-transform:none}#buddypress #rtm-media-options-list .rtm-options .rtmedia-delete-favlist{color:#fff;padding:0}#buddypress #rtm-media-options-list .rtm-options form button{font-size:14px}#buddypress #rtm-media-options-list .rtm-options i{line-height:1.7}.rtm-options.rtm-options{background:#666;color:#fff;display:none;font-size:14px;list-style:none;margin:0;padding:8px 10px;position:absolute;left:0;top:38px;width:190px;z-index:10}.rtm-options li{margin:0;overflow:hidden;padding:2px 0}.rtm-media-options .rtm-options:after{bottom:100%;left:20px;border:solid transparent;content:' ';height:0;width:0;position:absolute;pointer-events:none;border-color:rgba(255,255,255,0);border-bottom-color:#666;border-width:6px;margin-left:-6px}.mfp-content .rtm-options{background:#fff;color:#333;bottom:38px;right:0;left:auto;top:auto}.mfp-content .rtm-options:after{top:100%;right:22px;border:solid transparent;content:' ';height:0;width:0;position:absolute;pointer-events:none;border-color:rgba(255,255,255,0);border-top-color:#fff;border-width:6px;margin-left:-6px}.rtm-options .dashicons{font-size:14px;line-height:24px;margin-right:2px}.rtm-media-options .rtm-options a{border:0;color:#fff;display:block;text-decoration:none}.rtm-ltb-title{color:rgba(255,255,255,0.7);float:left;font-size:13px}.rtm-ltb-title a{color:inherit}.rtm-ltb-title a:hover{border-bottom:1px dotted;color:#fff}.rtm-item-actions{float:right}.rtm-item-actions>div,.rtm-item-actions>form{float:left;margin:0 4px 0 0;padding:7px 0;position:relative}.rtmedia-media{margin:0 auto}.rtmedia-media img{display:inline-block;max-height:inherit;height:auto;max-width:100%;width:auto}@media only screen and (max-device-width: 1024px){.rtmedia-media{margin:40px 0}}.rtm-user-meta-details .username{font-size:16px;line-height:1;margin-bottom:6px}.userprofile{float:left;margin:0 16px 16px 0;max-width:54px}.userprofile a{display:block}.userprofile img{height:auto;max-width:100%}.rtm-time-privacy{color:#999;font-size:12px}.rtm-time-privacy .dashicons{font-size:14px;line-height:1.5;margin-top:-2px}.rtmedia-actions-before-comments>span{float:left;margin-right:10px}.rtmedia-actions-before-comments .rtmedia-comment-link,.rtmedia-actions-before-comments .rtmedia-view-conversation,#buddypress .rtmedia-actions-before-comments .rtmedia-like{border:0;font-size:13px;font-weight:normal;line-height:2;padding:0;text-transform:none}.rtmedia-actions-before-comments .rtmedia-comment-link:hover,.rtmedia-actions-before-comments .rtmedia-view-conversation:hover,#buddypress .rtmedia-actions-before-comments .rtmedia-like:hover{background:transparent}.rtmedia-comment-user-pic{float:left;margin-right:10px;max-width:36px}.rtmedia-comment-user-pic img{height:auto;max-width:100%}.rtm-like-comments-info{position:relative}.rtm-like-comments-info:after{bottom:100%;left:15px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none;border-color:rgba(237,239,244,0);border-bottom-color:#edeff4;border-width:4px;margin-left:-4px}.rtm-comment-list.rtm-comment-list{height:340px;list-style:none;margin:0;overflow:auto;padding:0}.rtm-comment-list li{background:#edeff4;font-size:12px;margin-bottom:1px;padding:10px;position:relative}.rtm-comment-list li:hover .rtmedia-delete-comment{opacity:1}.rtm-comment-list .rtmedia-no-comments{margin:0;padding:5px 10px}.rtmedia-like-info{background:#edeff4;font-size:12px;margin-bottom:1px;padding:5px 10px;position:relative}.rtm-comment-wrap{overflow:hidden}.rtm-comment-wrap .rtmedia-comment-author{font-weight:700}.rtm-comment-wrap .rtmedia-comment-date{color:#999;font-size:11px}.rtmedia-comment-content{margin-top:2px}.rtmedia-delete-comment{color:#999;cursor:pointer;font-size:16px;opacity:0;position:absolute;right:5px;top:5px}.rtmedia-comment-content p{margin:0}.rtmedia-comment-details{line-height:1.5;margin-top:-3px}.rt_media_comment_form textarea{display:inline-block;margin-bottom:5px}.rtmedia-item-comments textarea{font-size:14px;padding:4px}.rtm-media-single-comments{bottom:20px;padding:10px;width:100%}.rtm-media-single-comments textarea{background-color:#edeff4;font-size:12px;line-height:14px;max-height:40px;min-height:30px;padding:4px}.rtmedia-popup{background:#fff;margin:20px auto;max-width:600px;padding:20px;position:relative;width:auto}.rtmedia-popup .rtm-modal-title{font-size:24px;margin-bottom:20px;margin-top:0}.rtmedia-popup label{display:block;margin-bottom:5px}#rtm-modal-container p{margin-bottom:10px}#rtm-mejs-video-container{margin:0 auto}.rtmedia-media-name{float:left;max-width:140px;overflow:hidden;text-align:left;text-overflow:ellipsis;white-space:nowrap}.rtm-single-media.rtm-media-type-video{padding-bottom:40px;padding-top:40px}.rtmedia-gallery-alert-container{position:fixed;top:0;left:0;height:100%;width:100%;background-color:rgba(0,0,0,0.6);z-index:999997}.rtmedia-gallery-message-box{position:fixed;top:40%;left:50%;margin-left:auto;margin-right:auto;z-index:999999}.rtmedia-gallery-message-box span{position:relative;left:-50%}#mobile-swipe-overlay{position:absolute;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(255,255,255,0.7);z-index:15;cursor:pointer}#mobile-swipe-overlay .swipe-icon{position:absolute;top:30%;left:50%;font-size:50px;color:#000;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);width:200px}#mobile-swipe-overlay .swipe-icon img{width:100%}#mobile-swipe-overlay .swipe-tootlip{font-weight:800;position:absolute;padding:20px;top:45%;width:100%;text-align:center}.rtmedia-activity-container{box-sizing:border-box}.rtmedia-activity-container *,.rtmedia-activity-container *:before,.rtmedia-activity-container *:after{box-sizing:inherit}.rtmedia-activity-container .rtmedia-list.masonry{list-style:none;padding:0}.rtmedia-activity-container .rtmedia-list.masonry p{display:none}.rtmedia-activity-container .rtmedia-list.masonry:after{content:'';display:block;clear:both}.rtmedia-activity-container .rtmedia-list-item.masonry-brick{display:inline-block;float:left;width:32%;padding:0 !important}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container{min-width:33% !important;margin:0 0 5px 0;width:100% !important}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls{width:100%}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-time-total{display:none}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-horizontal-volume-slider{width:20%;padding-left:5px}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total{width:100%}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-time-loaded{display:none}.rtmedia-activity-container .rtmedia-list-item.masonry-brick img{display:block;max-width:100%}.rtmedia-activity-container .rtmedia-list-item.masonry-brick .rtmedia-item-title{display:none}#buddypress ul.rtmedia-list li{border-bottom:0;padding-bottom:0}.rtmedia-activity-container .rtmedia-item-actions{display:none}.rtmedia-activity-container .rtmedia-item-title,.rtmedia-activity-container .rtmedia-item-title a{border:0;color:#666;font-size:13px;margin:5px 0 0;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}#rtmedia-whts-new-upload-container div{left:0 !important;position:absolute;top:0 !important}#aw-whats-new-submit,.rtmedia-add-media-button{display:block}.rtm-drag-drop-active{border:4px dashed green !important;display:block;height:100%;opacity:0.5;z-index:9999}#rtm-drop-files-title{background:rgba(0,0,0,0.2);display:none;font-size:14px;height:100%;padding:20px;position:absolute;top:0;width:100%}#rtSelectPrivacy{float:right}form.rt_media_comment_form .rtmedia-plupload-container{overflow:hidden}.rtmedia-plupload-container{position:relative;float:left}.rtm-upload-button-wrapper{float:left;margin-right:5px}#rtmedia-action-update{margin-right:10px}.rtmedia-list-item.media-type-photo,.rtmedia-list-item.media-type-document,.rtmedia-list-item.media-type-music,.rtmedia-list-item.media-type-video{display:inline-block}.media-type-music .mejs-container{margin-bottom:10px}.previous-pagination{float:left;margin-top:10px}.next-pagination{float:right;margin-top:10px}@media screen and (max-width: 500px){#activity-stream li .media-type-video{width:100%}#activity-stream li .media-type-video .mejs-video{max-width:100%;min-width:100%}}#rtmedia_show_all_comment{cursor:pointer}#rtmedia_show_all_comment:hover{text-decoration:underline}#whats-new-options{opacity:0;display:none}#whats-new-options .rtmedia-uploader-div{opacity:0;display:none;visibility:hidden}.bp-nouveau .activity-update-form .rtmedia-uploader-div{margin-left:8.5%}.bp-nouveau .activity-update-form .rtmedia-plupload-container{width:25%}.bp-nouveau .activity-update-form .rtmedia-upload-terms #rtmedia_upload_terms_conditions{margin-left:20px}.bp-nouveau .activity-update-form #aw-whats-new-submit{margin-top:15px}.ac-form .rtmedia-uploader-div,.rt_media_comment_form .rtmedia-uploader-div{opacity:1;display:block;visibility:visible}#whats-new-options{opacity:0;display:none}a.rtmedia-comment-link{display:none}a.rtmedia-comment-link.rtmedia-comments-link{display:initial}.rtmedia-album-edit .rtm-checkbox-wrap{background:rgba(255,255,255,0.9);height:30px;line-height:1;padding:10px;position:absolute;z-index:10}.rtmedia-album-edit .rtmedia-item-selector{position:relative;top:-7px}.rtmedia-album-edit .rtmedia-move-container{display:none}.rtm-single-actions.rtm-item-actions{float:none}.rtm-media-type-music .rtmedia-media{width:100%}.media-item .describe{border-collapse:collapse;width:100%;border-top-style:solid;border-top-width:1px;clear:both;cursor:default}.media-item.media-blank .describe{border:0}.media-item .describe th{vertical-align:top;text-align:left;padding:5px 10px 10px;width:140px}.media-item .describe .align th{padding-top:0}.media-item .media-item-info tr{background-color:transparent}.media-item .describe td{padding:0 8px 8px 0;vertical-align:top}.media-item thead.media-item-info td{padding:4px 10px 0}.media-item .media-item-info .A1B1{padding:0 0 0 10px}.media-item td.savesend{padding-bottom:15px}.media-item .thumbnail{max-height:128px;max-width:128px}#wpbody-content #async-upload-wrap a{display:none}.media-upload-form{margin-top:20px}.media-upload-form td label{margin-right:6px;margin-left:2px}.media-upload-form .align .field label{display:inline;padding:0 0 0 23px;margin:0 1em 0 3px;font-weight:bold}.media-upload-form tr.image-size label{margin:0 0 0 5px;font-weight:bold}.media-upload-form th.label label{font-weight:bold;margin:0.5em;font-size:13px}.media-upload-form th.label label span{padding:0 5px}abbr.required{border:medium none;text-decoration:none}.media-item .describe input[type="text"],.media-item .describe textarea{width:460px}.media-item .describe p.help{margin:0;padding:0 0 0 5px}.media-item .edit-attachment,.describe-toggle-on,.describe-toggle-off{display:block;line-height:36px;float:right;margin-right:15px}.media-item .describe-toggle-off,.media-item.open .describe-toggle-on{display:none}.media-item.open .describe-toggle-off{display:block}#media-items .media-item{border-style:solid;border-width:1px;min-height:36px;position:relative;margin-top:-1px;width:100%}#media-items{width:623px}.media-new-php #media-items{margin:1em 0}#media-items:empty{border:0 none}.media-item .filename{line-height:36px;overflow:hidden;padding:0 10px}.media-item .error-div{padding-left:10px}.media-item .pinkynail{float:left;margin:2px 2px 0;max-width:40px;max-height:32px}.media-item .startopen,.media-item .startclosed{display:none}.media-item .original{position:relative;height:34px}.media-item .progress{float:right;height:22px;margin:6px 10px 0 0;width:200px;line-height:2em;padding:0;overflow:hidden;margin-bottom:2px;border:1px solid #d1d1d1;background:#f7f7f7;background-image:-webkit-gradient(linear, left bottom, left top, from(#fff), to(#f7f7f7));background-image:-webkit-linear-gradient(bottom, #fff, #f7f7f7);background-image:linear-gradient(to top, #fff, #f7f7f7);border-radius:3px;box-shadow:inset 0 0 3px rgba(0,0,0,0.1)}.media-item .bar{z-index:9;width:0;height:100%;margin-top:-24px;background-color:#8cc1e9;background-image:-webkit-gradient(linear, left bottom, left top, from(#72a7cf), to(#8cc1e9));background-image:-webkit-linear-gradient(bottom, #72a7cf, #8cc1e9);background-image:linear-gradient(to top, #72a7cf, #8cc1e9);border-radius:3px;box-shadow:0 0 3px rgba(0,0,0,0.3)}.media-item .progress .percent{z-index:10;position:relative;width:200px;padding:0 8px;text-shadow:0 1px 0 rgba(255,255,255,0.4);color:rgba(0,0,0,0.6)}.upload-php .fixed .column-parent{width:15%}.js .html-uploader #plupload-upload-ui{display:none}.js .html-uploader #html-upload-ui{display:block}.media-upload-form .media-item.error{margin:0;padding:0}.media-upload-form .media-item.error p,.media-item .error-div{line-height:16px;margin:5px 10px;padding:0}.media-item .error-div a.dismiss{display:block;float:right;margin:5px 4px 0 15px}.find-box{width:600px;height:300px;overflow:hidden;padding:33px 0 51px;position:absolute;z-index:1000}.find-box-head{cursor:move;font-weight:bold;height:2em;line-height:2em;padding:1px 12px;position:absolute;top:5px;width:100%}.find-box-inside{overflow:auto;padding:6px;height:100%}.find-box-search{overflow:hidden;padding:9px;position:relative}.find-box-search .spinner{float:none;left:125px;position:absolute;top:9px}#find-posts-input{float:left;width:140px;height:24px}#find-posts-search{float:left;margin:1px 4px 0 3px}#find-posts-response{margin:8px 0;padding:0 1px 6px}#find-posts-response table{width:100%}#find-posts-response .found-radio{padding:3px 0 0 8px;width:15px}.find-box-buttons{padding:8px;overflow:hidden}.find-box #resize-se{position:absolute;right:1px;bottom:1px}.ui-find-overlay{position:absolute;top:0;left:0;background-color:#000;opacity:0.6;filter:alpha(opacity=60)}ul#dismissed-updates{display:none}form.upgrade{margin-top:8px}form.upgrade .hint{font-style:italic;font-size:85%;margin:-0.5em 0 2em 0}#poststuff .inside .the-tagcloud{margin:5px 0 10px;padding:8px;border-width:1px;border-style:solid;line-height:1.8em;word-spacing:3px;border-radius:6px}.drag-drop #drag-drop-area{border:4px dashed #DDDDDD;height:200px}.drag-drop .drag-drop-inside{margin:70px auto 0;width:250px}.drag-drop-inside p{color:#aaa;font-size:14px;margin:5px 0;display:none}.drag-drop .drag-drop-inside p{text-align:center}.drag-drop-inside p.drag-drop-info{font-size:20px}.drag-drop .drag-drop-inside p,.drag-drop-inside p.drag-drop-buttons{display:block}.drag-drop.drag-over #drag-drop-area{border-color:#83b4d8}#plupload-upload-ui{position:relative}.describe .image-editor{vertical-align:top}.imgedit-wrap{position:relative}#item-body .imgedit-settings .imgedit-group-top h2{display:inline-block;margin:0}.rtmedia-container .rtmedia-image-editor-cotnainer label{display:inline-block;float:none;margin-right:0}.rtmedia-container .rtmedia-image-editor-cotnainer .dashicons-editor-help{padding:0;height:auto;margin-top:10px}.rtmedia-container .rtmedia-image-editor-cotnainer .hidden{display:none}.imgedit-settings p{margin:8px 0}.post-php .imgedit-wrap table{width:100%}.describe .imgedit-wrap table td,.wp_attachment_holder .imgedit-wrap table td{vertical-align:top;padding-top:0}.describe .imgedit-wrap table td.imgedit-settings{padding:0 5px}.wp_attachment_holder .imgedit-wrap table td.imgedit-settings{width:250px}td.imgedit-settings input{margin-top:0;vertical-align:middle}.imgedit-wait{position:absolute;top:0;background:#fff url(../../../../../../wp-admin/images/wpspin_light.gif) no-repeat scroll 22px 10px;background-size:16px 16px;opacity:0.7;filter:alpha(opacity=70);width:100%;height:500px;display:none}.spinner{background:url(../../../../../../wp-admin/images/wpspin_light.gif) no-repeat;background-size:16px 16px;display:none;float:right;opacity:0.7;filter:alpha(opacity=70);width:16px;height:16px;margin:5px 5px 0}.no-float{float:none}.media-disabled,.imgedit-settings .disabled{color:grey}.wp_attachment_image,.A1B1{overflow:hidden}.wp_attachment_image .button,.A1B1 .button{float:left}.no-js .wp_attachment_image .button{display:none}.wp_attachment_image .spinner,.A1B1 .spinner{float:left;padding:0 4px 4px;vertical-align:bottom}.imgedit-menu{margin:0 0 12px;min-width:300px}.imgedit-menu div{float:left;width:32px;height:32px}.imgedit-crop-wrap{position:relative}.imgedit-crop{margin:0 8px 0 0}.imgedit-crop.disabled:hover{background-position:-9px -31px}.imgedit-crop:hover{background-position:-9px -1px}.imgedit-rleft{margin:0 3px}.imgedit-rleft.disabled:hover{background-position:-46px -31px}.imgedit-rleft:hover{background-position:-46px -1px}.imgedit-rright{margin:0 8px 0 3px}.imgedit-rright.disabled:hover{background-position:-77px -31px}.imgedit-rright:hover{background-position:-77px -1px}.imgedit-flipv{margin:0 3px}.imgedit-flipv.disabled:hover{background-position:-115px -31px}.imgedit-flipv:hover{background-position:-115px -1px}.imgedit-fliph{margin:0 8px 0 3px}.imgedit-fliph.disabled:hover{background-position:-147px -31px}.imgedit-fliph:hover{background-position:-147px -1px}.imgedit-undo{margin:0 3px}.imgedit-undo.disabled:hover{background-position:-184px -31px}.imgedit-undo:hover{background-position:-184px -1px}.imgedit-redo{margin:0 8px 0 3px}.imgedit-redo.disabled:hover{background-position:-215px -31px}.imgedit-redo:hover{background-position:-215px -1px}.imgedit-applyto img{margin:0 8px 0 0}.imgedit-group h3{font-size:18px}.imgedit-group .dashicons{border:0;line-height:1.2}.imgedit-group-top{margin:5px 0}.imgedit-applyto .imgedit-label{padding:2px 0 0;display:block}.imgedit-help{display:none;font-style:italic;margin-bottom:8px}a.imgedit-help-toggle{text-decoration:none}.form-table td.imgedit-response{padding:0}.imgedit-submit{margin:8px 0}.imgedit-submit-btn{margin-left:20px}.imgedit-wrap .nowrap{white-space:nowrap}span.imgedit-scale-warn{color:red;font-size:20px;font-style:normal;visibility:hidden;vertical-align:middle}.wp_attachment_details{margin-bottom:20px}.imgedit-menu div{border-color:#d5d5d5;background-color:#f1f1f1}.imgedit-menu div:hover{border-color:#c1c1c1;background-color:#eaeaea}.imgedit-menu div.disabled{border-color:#ccc;background-color:#ddd;filter:alpha(opacity=50);opacity:0.5}.bp-media-image-editor-cotnainer{margin-top:35px}.wp_attachment_image .bp-media-image-edit{float:left}.wp_attachment_image .spinner{display:none}.bp-media-image-editor-cotnainer .hidden{display:none}.bp-media-image-editor-cotnainer div.updated{margin:5px 0 15px;background-color:#ffffe0;border-color:#e6db55;padding:0 .6em;border-radius:3px;border-width:1px;border-style:solid}.bp-media-image-editor-cotnainer div.updated p{margin:.5em 0;padding:2px}body article.bp_members.bp_member .entry-content,body div.bp_members.bp_member .entry-content{width:100%}.rtm-media-gallery-uploader{display:none}h2.rtm-gallery-title{margin:10px 0}.rtmedia-uploader .drag-drop{border:4px dashed #DDD;text-align:center;background:#fafafa;overflow:hidden;color:#AAAAAA;margin-top:20px;padding:25px 0}.rtmedia-uploader .drag-drop.dragover{border-color:#83b4d8}.rtmedia-uploader .drag-drop .drag-drop-info{font-size:20px;line-height:24px}.rtmedia-uploader .drag-drop .rtm-select-files span{vertical-align:middle}.rtmedia-uploader .drag-drop .rtm-seperator{margin:0px 20px}.rtmedia-uploader .drag-drop .start-media-upload{display:none;margin-top:20px}.rtmedia-uploader .drag-drop .rtm-file-size-limit{vertical-align:middle;font-size:16px;line-height:24px}.rtm-uploader-main-wrapper .rtm-uploader-tabs{margin-bottom:10px;text-align:left}.rtm-uploader-main-wrapper ul{border-bottom:1px solid #CCC}.rtm-uploader-main-wrapper li{margin:0 0 -1px 10px;display:inline-block;padding:5px 10px;line-height:25px;background-color:#e4e4e4;border:1px solid #CCC}.rtm-uploader-main-wrapper li.active{background:transparent;border-left:1px solid #CCC;border-top:1px solid #CCC;border-right:1px solid #CCC;border-bottom:1px solid #fafafa}.rtm-uploader-main-wrapper li:hover{cursor:pointer}.rtmedia-container .rtmedia-list{margin:10px -5px}.rtmedia-container .rtmedia-list .rtmedia-list-item{float:left;margin:5px;position:relative}.rtmedia-container .rtmedia-list .rtmedia-list-item>a{display:block}.rtmedia-container .rtmedia-list .rtmedia_time{background-color:#000;color:#fff;display:inline-block;font-size:11px;font-weight:bold;line-height:14px;opacity:0.75;padding:0 4px;position:absolute;right:2px;top:2px}.rtmedia-container .rtmedia-list img{vertical-align:top}.rtmedia-container .rtmedia-list .rtmedia-item-title h4{color:#666;font-size:12px;font-weight:normal;margin:5px 0 0;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}.rtm-load-more{background:#eee;text-align:center}.rtmedia-container .rtm-load-more a{border:0;padding:10px 0}.rtm-load-more .rtm-media-loading{padding:10px 0}.rtm-media-options.rtm-media-search-enable>*:nth-last-child(2){border-right:none}.rtm-media-options{line-height:1.4;margin-bottom:10px;clear:both}.rtm-media-options>div{display:inline-block;cursor:pointer}.rtm-media-options .rtm-media-options-list{margin-right:5px;padding-right:10px;position:relative}.rtm-media-options>*{border-right:1px solid #999}.rtm-media-options>*:last-child{border-right:none}.rtm-media-options .dashicons{font-size:inherit;line-height:1.4}#buddypress .media_search.media_search .search_by{margin-top:3px}.bp-legacy.media #buddypress #item-header-cover-image .user-nicename{margin-bottom:20px}.bp-legacy.media #buddypress div#item-header div#item-header-content ul li,.bp-legacy.media #buddypress div#item-header div#item-header-content ul div{float:left;margin:2px 10px}.bp-legacy.media #buddypress div#item-header div#item-header-content button,.bp-legacy.media #buddypress div#item-header div#item-header-content a{background:#fff;border:1px solid #ccc;color:#767676;font-size:small;cursor:pointer;outline:none;padding:4px 10px;text-align:center;text-decoration:none}.bp-legacy.media #buddypress div#item-header div#item-header-content button:hover,.bp-legacy.media #buddypress div#item-header div#item-header-content a:hover{background:#ededed;border:1px solid #bbb;color:#555;outline:none}.bp-nouveau.media .entry-title{font-size:34px;font-weight:inherit;margin-bottom:0}.bp-nouveau.media .entry-title a{color:#767676}.bp-nouveau.media #buddypress #item-header-cover-image .user-nicename{margin-top:15px;margin-bottom:30px}.bp-nouveau.media #buddypress div#item-header div#item-header-content ul li,.bp-nouveau.media #buddypress div#item-header div#item-header-content ul div{float:left;margin:2px 10px}.bp-nouveau.media #buddypress div#item-header div#item-header-content button,.bp-nouveau.media #buddypress div#item-header div#item-header-content a{background:#fff;border-color:#ccc;border-style:solid;border-width:1px;color:#555;cursor:pointer;font-size:inherit;font-weight:400;outline:none;padding:0.3em 0.5em;text-align:center;text-decoration:none;width:auto}.bp-nouveau.media #buddypress div#item-header div#item-header-content button:hover,.bp-nouveau.media #buddypress div#item-header div#item-header-content a:hover{background:#ededed;border-color:#999999;color:#333;outline:none;text-decoration:none}.media_search.media_search{float:right;border:1px solid #ccc;margin-left:5px;padding:3px 0}.media_search.media_search .media_search_input{width:200px;outline:0;max-width:200px;margin:0;box-shadow:none;padding:5px 6px;border:none;background:transparent;float:left;max-height:30px}.media_search.media_search #media_fatch_loader.load{float:left;width:20px;height:30px;position:relative}.media_search.media_search #media_fatch_loader.load:before{content:'';border-radius:50%;border:1px solid #aaa;border-top-color:rgba(255,255,255,0.9);animation:spinner .8s linear infinite;-webkit-animation:spinner .8s linear infinite;position:absolute;width:15px;height:15px;top:24%}.media_search.media_search .search_option{padding:0;background:transparent;color:#000;margin-bottom:0;line-height:1;border:none}.media_search.media_search .media_search_remove.search_option{display:none}.media_search.media_search .media_search_remove.search_option i{margin-top:4px}.media_search.media_search .search_by{background:transparent;margin-top:3px;float:left;width:auto;margin-bottom:0;height:auto;padding-top:0;padding-bottom:0}@keyframes spinner{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner{to{-webkit-transform:rotate(360deg)}}.rtmedia-upload-media-link{cursor:pointer}a.rtmedia-upload-media-link{border:none}.rtm-album-privacy span{font-size:16px;display:inline-block;margin:0 20px 20px 20px;vertical-align:top}.rtm-album-privacy label{margin-right:8px}.rtm-album-privacy .dashicons{font-size:16px;line-height:1.6;margin-right:5px}#rtm-media-options-list .rtmedia-delete-album{background:transparent;border:0;color:#fff;font-family:inherit;font-size:inherit;font-weight:inherit;padding:0;text-transform:inherit}#rtm-media-options-list .rtmedia-delete-album:hover{background:transparent;border:0;color:#fff}.rtmedia-single-container button.rtmedia-like{background-color:transparent;color:inherit}#buddypress #item-body{padding:0 20px}#buddypress .mejs-controls button{padding:4px 8px;border:none;background:transparent url("../../../lib/media-element/mejs-controls.png") no-repeat}#buddypress .mejs-controls .mejs-play>button{background-position:0 0}#buddypress .mejs-controls .mejs-pause>button{background-position:-20px 0}#buddypress .mejs-controls .mejs-unmute>button{background-position:-40px 0}#buddypress .mejs-controls .mejs-mute>button{background-position:-60px 0}#buddypress .mejs-controls .mejs-fullscreen-button>button{background-position:-80px 0}#buddypress .mejs-controls .mejs-unfullscreen>button{background-position:-100px 0}#buddypress .mejs-controls .mejs-replay>button{background-position:-160px 0}.mejs-container .mejs-controls .mejs-time{padding:15px 3px 0;content:''}.rtmedia-activity-container .mejs-playpause-button.mejs-play button:before,.rtmedia-activity-container .mejs-playpause-button.mejs-pause button:before,.rtmedia-activity-container .mejs-volume-button.mejs-mute button:before,.rtmedia-activity-container .mejs-fullscreen-button button:before,.rtmedia-media .mejs-playpause-button.mejs-play button:before,.rtmedia-media .mejs-playpause-button.mejs-pause button:before,.rtmedia-media .mejs-volume-button.mejs-mute button:before,.rtmedia-media .mejs-fullscreen-button button:before{content:''}@media only screen and (min-width: 1025px){.mfp-content .rtm-lightbox-container{display:-webkit-box;display:-ms-flexbox;display:flex;table-layout:fixed;width:100%;min-height:473px}.mfp-content .rtm-mfp-close{background:transparent}.mfp-content .rtm-single-media{display:-webkit-box;display:-ms-flexbox;display:flex;width:66.6667%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.mfp-content .rtm-single-meta{display:block;width:33.3333%;padding:20px}.mfp-content .rtm-single-meta .rtmedia-scroll{height:100%;overflow-X:hidden}}.rtl #rtSelectPrivacy{float:left}.rtl .rtmedia-plupload-container{float:right}.rtl .rtm-upload-button-wrapper{float:right}.rtl #whats-new-post-in-box{float:right}.rtl .describe-toggle-off{float:left}.rtl .media-item .pinkynail{float:right}.rtl .media-item .progress{float:left}.rtl .media-item .error-div a.dismiss{float:left}.rtl #find-posts-input{float:right}.rtl #find-posts-search{float:right}.rtl .spinner{float:left}.rtl .wp_attachment_image .button,.rtl .A1B1 .button{float:right}.rtl .wp_attachment_image .spinner,.rtl .A1B1 .spinner{float:right}.rtl .imgedit-menu div{float:right}.rtl .wp_attachment_image .bp-media-image-edit{float:right}.rtl .rtmedia-container .rtmedia-list .rtmedia-list-item{float:right}.rtl #buddypress #rtm-media-options-list .rtm-options .button{float:right}.rtl .rtm-ltb-title{float:right}.rtl .rtm-item-actions{float:left}.rtl .rtm-item-actions>div,.rtl .rtm-item-actions>form{float:right}.rtl .userprofile{float:right}.rtl .rtmedia-actions-before-comments>span{float:right}.rtl .rtmedia-comment-user-pic{float:right}.rtl .rtmedia-media-name{float:right}.rtl #rtmedia-uploader-form .rtm-plupload-list li,.rtl #rtmedia_uploader_filelist li{float:right}.rtl .rtm-page-number{float:right}.rtl .rtm-page-number .rtmedia-page-link{float:right}.rtl .rtm-pagination{float:right}.rtl .rtm-pagination .rtm-paginate{float:left}.rtl .rtm-tabs li{float:right}.rtl .alignleft{float:right}.rtl .alignright{float:left}
app/assets/css/sass/_media-tab.scss CHANGED
@@ -11,6 +11,10 @@ body {
11
  display: none;
12
  }
13
 
 
 
 
 
14
  .rtmedia-uploader {
15
  .drag-drop {
16
  border: 4px dashed #DDD;
11
  display: none;
12
  }
13
 
14
+ h2.rtm-gallery-title {
15
+ margin: 10px 0;
16
+ }
17
+
18
  .rtmedia-uploader {
19
  .drag-drop {
20
  border: 4px dashed #DDD;
app/assets/css/sass/_popup.scss CHANGED
@@ -1,7 +1,7 @@
1
  /*
2
  * popup autocomplete
3
  */
4
- #atwho-container {
5
  #atwho-ground-comment_content {
6
  .atwho-view {
7
  z-index: 2147483647;
@@ -124,14 +124,6 @@
124
  }
125
  }
126
 
127
- #buddypress #rtm-media-options-list {
128
- .rtm-options {
129
- form button {
130
- font-size: small;
131
- }
132
- }
133
- }
134
-
135
  #buddypress #rtm-media-options-list {
136
  .rtm-options {
137
  .button {
@@ -144,7 +136,6 @@
144
  font-weight: normal;
145
  line-height: 24px;
146
  padding: 0 6px;
147
- text-shadow: 0 0 0;
148
  text-transform: none;
149
  }
150
 
@@ -152,6 +143,14 @@
152
  color: $white;
153
  padding: 0;
154
  }
 
 
 
 
 
 
 
 
155
  }
156
  }
157
 
1
  /*
2
  * popup autocomplete
3
  */
4
+ .atwho-container {
5
  #atwho-ground-comment_content {
6
  .atwho-view {
7
  z-index: 2147483647;
124
  }
125
  }
126
 
 
 
 
 
 
 
 
 
127
  #buddypress #rtm-media-options-list {
128
  .rtm-options {
129
  .button {
136
  font-weight: normal;
137
  line-height: 24px;
138
  padding: 0 6px;
 
139
  text-transform: none;
140
  }
141
 
143
  color: $white;
144
  padding: 0;
145
  }
146
+
147
+ form button {
148
+ font-size: 14px;
149
+ }
150
+
151
+ i {
152
+ line-height: 1.7;
153
+ }
154
  }
155
  }
156
 
app/assets/css/sass/_rtm.scss CHANGED
@@ -200,9 +200,14 @@ button#rtmedia-add-media-button-post-update {
200
  }
201
 
202
  #buddypress {
203
- a.rtm-button-back{
204
- padding: 3px 10px;
 
 
 
 
205
  }
 
206
  }
207
 
208
  // Pagination
@@ -222,6 +227,10 @@ button#rtmedia-add-media-button-post-update {
222
  .rtmedia-page-link {
223
  float: left;
224
  }
 
 
 
 
225
  }
226
 
227
  .rtm-pagination {
@@ -264,12 +273,13 @@ button#rtmedia-add-media-button-post-update {
264
  padding: 0;
265
  width: auto;
266
  }
 
267
  }
268
 
269
  #rtmedia_go_to_num {
270
  font-size: 16px;
271
  margin: 0 5px;
272
- padding: 4px 5px;
273
  width: 80px;
274
  }
275
 
200
  }
201
 
202
  #buddypress {
203
+ a.rtm-button-back{
204
+ padding: 3px 10px;
205
+ }
206
+ div.rtmedia-page-no.rtm-page-number {
207
+ a.rtmedia-page-link.button {
208
+ padding: 5px 10px;
209
  }
210
+ }
211
  }
212
 
213
  // Pagination
227
  .rtmedia-page-link {
228
  float: left;
229
  }
230
+ .rtm-go-to-num,
231
+ .rtmedia-page-link {
232
+ line-height: 1.5;
233
+ }
234
  }
235
 
236
  .rtm-pagination {
273
  padding: 0;
274
  width: auto;
275
  }
276
+
277
  }
278
 
279
  #rtmedia_go_to_num {
280
  font-size: 16px;
281
  margin: 0 5px;
282
+ padding: 3px 5px;
283
  width: 80px;
284
  }
285
 
app/assets/js/rtMedia.backbone.js CHANGED
@@ -684,7 +684,7 @@ jQuery( function( $ ) {
684
 
685
  // Show/create text box to edit media title
686
  if ( jQuery( rtm_file_title_input ).length === 0 ) {
687
- jQuery( rtm_file_label ).parent( '.plupload_file_name' ).prepend( '<div id="' + rtm_file_title_wrapper_id + '" class="rtm-upload-edit-title-wrapper"><label>' + rtmedia_edit_media_info_upload.title + '</label><input type="text" class="rtm-upload-edit-title" id="' + rtm_file_title_id + '" value="' + file.title + '" style="width: 75%;" /></div><div id="' + rtm_file_desc_wrapper_id + '" class="rtm-upload-edit-desc-wrapper"><label>' + rtmedia_edit_media_info_upload.description + '</label><textarea class="rtm-upload-edit-desc" id="' + rtm_file_desc_id + '"></textarea></div><span id="' + rtm_file_save_id + '" title="Save Change" class="rtmicon dashicons dashicons-yes"></span>' );
688
  } else {
689
  jQuery( rtm_file_title_wrapper ).show();
690
  jQuery( rtm_file_desc_wrapper ).show();
@@ -879,7 +879,7 @@ jQuery( function( $ ) {
879
  activity_id = rtnObj.activity_id;
880
  if ( rtnObj.permalink != '' ) {
881
  $( "#" + file.id + " .plupload_file_name" ).html( "<a href='" + rtnObj.permalink + "' target='_blank' title='" + rtnObj.permalink + "'>" + file.title.substring( 0, 40 ).replace( /(<([^>]+)>)/ig, "" ) + "</a>" );
882
- $( "#" + file.id + " .plupload_media_edit" ).html( "<a href='" + rtnObj.permalink + "edit' target='_blank'><span title='" + rtmedia_edit_media + "'><i class='dashicons dashicons-edit rtmicon'></i> " + rtmedia_edit + "</span></a>" );
883
  $( "#" + file.id + " .plupload_delete" ).html( "<span id='" + rtnObj.media_id + "' class='rtmedia-delete-uploaded-media dashicons dashicons-dismiss' title='" + rtmedia_delete + "'></span>" );
884
  }
885
 
@@ -1227,7 +1227,7 @@ jQuery( document ).ready( function( $ ) {
1227
 
1228
  // Show/create text box to edit media title
1229
  if ( jQuery( rtm_file_title_input ).length === 0 ) {
1230
- jQuery( rtm_file_label ).parent( '.plupload_file_name' ).prepend( '<div id="' + rtm_file_title_wrapper_id + '" class="rtm-upload-edit-title-wrapper"><label>' + rtmedia_edit_media_info_upload.title + '</label><input type="text" class="rtm-upload-edit-title" id="' + rtm_file_title_id + '" value="' + file.title + '" style="width: 75%;" /></div><div id="' + rtm_file_desc_wrapper_id + '" class="rtm-upload-edit-desc-wrapper"><label>' + rtmedia_edit_media_info_upload.description + '</label><textarea class="rtm-upload-edit-desc" id="' + rtm_file_desc_id + '"></textarea></div><span id="' + rtm_file_save_id + '" title="Save Change" class="rtmicon dashicons dashicons-yes"></span>' );
1231
  } else {
1232
  jQuery( rtm_file_title_wrapper ).show();
1233
  jQuery( rtm_file_desc_wrapper ).show();
@@ -1292,10 +1292,12 @@ jQuery( document ).ready( function( $ ) {
1292
  * if user want media and activity_text both require
1293
  * By: Yahil
1294
  */
1295
- if ( jQuery.trim( jQuery( "#whats-new" ).val() ) == "" ) {
1296
- if ( rtmedia_activity_text_with_attachment == 'disable') {
1297
- $( "#whats-new" ).css( 'color', 'transparent' );
1298
- $( "#whats-new" ).val( '&nbsp;' );
 
 
1299
  } else {
1300
  jQuery('#whats-new-form').prepend('<div id="message" class="error bp-ajax-message" style="display: block;"><p> ' + rtmedia_empty_activity_msg + ' </p></div>')
1301
  jQuery( '#whats-new' ).removeAttr( 'disabled' );
@@ -1392,11 +1394,15 @@ jQuery( document ).ready( function( $ ) {
1392
  }
1393
  } );
1394
 
1395
- var object = '';
1396
- var item_id = jQuery( '#whats-new-post-in' ).val();
1397
- if ( item_id == undefined ) {
1398
- item_id = 0;
1399
- }
 
 
 
 
1400
  if ( item_id > 0 ) {
1401
  object = 'group';
1402
  } else {
@@ -1687,10 +1693,10 @@ jQuery( document ).ready( function( $ ) {
1687
 
1688
 
1689
  $( this ).attr( 'disabled', 'disabled' );
1690
-
1691
- // Sanitize comment content and escape html tags
1692
- comment_content_el.val( jQuery( '<span/>' ).text( jQuery.trim( comment_content_el.val() ) ).html() );
1693
-
1694
  $.ajax( {
1695
  url: comment_form_el.attr( 'action' ),
1696
  type: 'post',
@@ -1783,6 +1789,7 @@ jQuery( document ).ready( function( $ ) {
1783
  }
1784
 
1785
  $( '.rtmedia-like span' ).html( data.next );
 
1786
  $( '.rtmedia-like-counter-wrap' ).html( data.person_text );
1787
  $( '.rtm-like-loading' ).remove();
1788
  $( that ).removeAttr( 'disabled' );
@@ -1888,15 +1895,15 @@ function rtmedia_selected_file_list( plupload, file, uploader, error, comment_me
1888
  if ( error == '' ) {
1889
  upload_progress = '<div class="plupload_file_progress ui-widget-header" style="width: 0%;">';
1890
  upload_progress += '</div>';
1891
- icon = '<span id="label_' + file.id + '" class="dashicons dashicons-edit rtmicon" title="' + rtmedia_backbone_strings.rtm_edit_file_name + '"></span>';
1892
  } else if ( error.code == -600 ) {
1893
  err_msg = ( uploader != '' ) ? rtmedia_max_file_msg + uploader.settings.max_file_size : window.file_size_info;
1894
  title = 'title=\'' + err_msg + '\'';
1895
- icon = '<i class="dashicons dashicons-info rtmicon" ' + title + '></i>';
1896
  } else if ( error.code == -601 ) {
1897
  err_msg = error.message + '. ' + window.file_extn_info;
1898
  title = 'title=\'' + err_msg + '\'';
1899
- icon = '<i class="dashicons dashicons-info rtmicon" ' + title + '></i>';
1900
  }
1901
 
1902
  var rtmedia_plupload_file = '<li class="plupload_file ui-state-default plupload_queue_li" id="' + file.id + '" ' + title + '>';
@@ -2407,6 +2414,7 @@ function renderUploadercomment_media( widget_id, parent_id_type ) {
2407
  jQuery( input_file_el ).click();
2408
  file_dialog_open = false;
2409
  }
 
2410
  } );
2411
 
2412
  var form_html = jQuery( "."+comment_media_wrapper+widget_id );
@@ -2523,7 +2531,7 @@ function renderUploadercomment_media( widget_id, parent_id_type ) {
2523
 
2524
  // Show/create text box to edit media title
2525
  if ( jQuery( rtm_file_title_input ).length === 0 ) {
2526
- jQuery( rtm_file_label ).parent( '.plupload_file_name' ).prepend( '<div id="' + rtm_file_title_wrapper_id + '" class="rtm-upload-edit-title-wrapper"><label>' + rtmedia_edit_media_info_upload.title + '</label><input type="text" class="rtm-upload-edit-title" id="' + rtm_file_title_id + '" value="' + file.title + '" style="width: 75%;" /></div><div id="' + rtm_file_desc_wrapper_id + '" class="rtm-upload-edit-desc-wrapper"><label>' + rtmedia_edit_media_info_upload.description + '</label><textarea class="rtm-upload-edit-desc" id="' + rtm_file_desc_id + '"></textarea></div><span id="' + rtm_file_save_id + '" title="Save Change" class="rtmicon dashicons dashicons-yes"></span>' );
2527
  } else {
2528
  jQuery( rtm_file_title_wrapper ).show();
2529
  jQuery( rtm_file_desc_wrapper ).show();
684
 
685
  // Show/create text box to edit media title
686
  if ( jQuery( rtm_file_title_input ).length === 0 ) {
687
+ jQuery( rtm_file_label ).parent( '.plupload_file_name' ).prepend( '<div id="' + rtm_file_title_wrapper_id + '" class="rtm-upload-edit-title-wrapper"><label>' + rtmedia_edit_media_info_upload.title + '</label><input type="text" class="rtm-upload-edit-title" id="' + rtm_file_title_id + '" value="' + file.title + '" style="width: 75%;" /></div><div id="' + rtm_file_desc_wrapper_id + '" class="rtm-upload-edit-desc-wrapper"><label>' + rtmedia_edit_media_info_upload.description + '</label><textarea class="rtm-upload-edit-desc" id="' + rtm_file_desc_id + '"></textarea></div><span id="' + rtm_file_save_id + '" title="Save Change" class="dashicons dashicons-yes"></span>' );
688
  } else {
689
  jQuery( rtm_file_title_wrapper ).show();
690
  jQuery( rtm_file_desc_wrapper ).show();
879
  activity_id = rtnObj.activity_id;
880
  if ( rtnObj.permalink != '' ) {
881
  $( "#" + file.id + " .plupload_file_name" ).html( "<a href='" + rtnObj.permalink + "' target='_blank' title='" + rtnObj.permalink + "'>" + file.title.substring( 0, 40 ).replace( /(<([^>]+)>)/ig, "" ) + "</a>" );
882
+ $( "#" + file.id + " .plupload_media_edit" ).html( "<a href='" + rtnObj.permalink + "edit' target='_blank'><span title='" + rtmedia_edit_media + "'><i class='dashicons dashicons-edit'></i> " + rtmedia_edit + "</span></a>" );
883
  $( "#" + file.id + " .plupload_delete" ).html( "<span id='" + rtnObj.media_id + "' class='rtmedia-delete-uploaded-media dashicons dashicons-dismiss' title='" + rtmedia_delete + "'></span>" );
884
  }
885
 
1227
 
1228
  // Show/create text box to edit media title
1229
  if ( jQuery( rtm_file_title_input ).length === 0 ) {
1230
+ jQuery( rtm_file_label ).parent( '.plupload_file_name' ).prepend( '<div id="' + rtm_file_title_wrapper_id + '" class="rtm-upload-edit-title-wrapper"><label>' + rtmedia_edit_media_info_upload.title + '</label><input type="text" class="rtm-upload-edit-title" id="' + rtm_file_title_id + '" value="' + file.title + '" style="width: 75%;" /></div><div id="' + rtm_file_desc_wrapper_id + '" class="rtm-upload-edit-desc-wrapper"><label>' + rtmedia_edit_media_info_upload.description + '</label><textarea class="rtm-upload-edit-desc" id="' + rtm_file_desc_id + '"></textarea></div><span id="' + rtm_file_save_id + '" title="Save Change" class="dashicons dashicons-yes"></span>' );
1231
  } else {
1232
  jQuery( rtm_file_title_wrapper ).show();
1233
  jQuery( rtm_file_desc_wrapper ).show();
1292
  * if user want media and activity_text both require
1293
  * By: Yahil
1294
  */
1295
+ if ( '' === jQuery( '#whats-new' ).val().trim() ) {
1296
+ if ( rtmedia_activity_text_with_attachment == 'disable' ) {
1297
+ if ( 0 === jQuery( '#rtmedia_upload_terms_conditions' ).length ) {
1298
+ $( '#whats-new' ).css( 'color', 'transparent' );
1299
+ $( '#whats-new' ).val( '&nbsp;' );
1300
+ }
1301
  } else {
1302
  jQuery('#whats-new-form').prepend('<div id="message" class="error bp-ajax-message" style="display: block;"><p> ' + rtmedia_empty_activity_msg + ' </p></div>')
1303
  jQuery( '#whats-new' ).removeAttr( 'disabled' );
1394
  }
1395
  } );
1396
 
1397
+ var object = '';
1398
+ var item_id = 0;
1399
+
1400
+ if ( jQuery( '#whats-new-post-in' ).length ) {
1401
+ item_id = jQuery( '#whats-new-post-in' ).val();
1402
+ } else if ( jQuery( '.groups-header' ).length ) {
1403
+ item_id = jQuery( '.groups-header' ).attr( 'data-bp-item-id' );
1404
+ }
1405
+
1406
  if ( item_id > 0 ) {
1407
  object = 'group';
1408
  } else {
1693
 
1694
 
1695
  $( this ).attr( 'disabled', 'disabled' );
1696
+ //If string has only &nbsp; then set value as empty.
1697
+ if ( '' === comment_content_el.val().replace(/\&nbsp;/g, '' ) ) {
1698
+ comment_content_el.val( '' );
1699
+ }
1700
  $.ajax( {
1701
  url: comment_form_el.attr( 'action' ),
1702
  type: 'post',
1789
  }
1790
 
1791
  $( '.rtmedia-like span' ).html( data.next );
1792
+ $( '.rtmedia-like' ).attr( 'title', data.next );
1793
  $( '.rtmedia-like-counter-wrap' ).html( data.person_text );
1794
  $( '.rtm-like-loading' ).remove();
1795
  $( that ).removeAttr( 'disabled' );
1895
  if ( error == '' ) {
1896
  upload_progress = '<div class="plupload_file_progress ui-widget-header" style="width: 0%;">';
1897
  upload_progress += '</div>';
1898
+ icon = '<span id="label_' + file.id + '" class="dashicons dashicons-edit" title="' + rtmedia_backbone_strings.rtm_edit_file_name + '"></span>';
1899
  } else if ( error.code == -600 ) {
1900
  err_msg = ( uploader != '' ) ? rtmedia_max_file_msg + uploader.settings.max_file_size : window.file_size_info;
1901
  title = 'title=\'' + err_msg + '\'';
1902
+ icon = '<i class="dashicons dashicons-info" ' + title + '></i>';
1903
  } else if ( error.code == -601 ) {
1904
  err_msg = error.message + '. ' + window.file_extn_info;
1905
  title = 'title=\'' + err_msg + '\'';
1906
+ icon = '<i class="dashicons dashicons-info" ' + title + '></i>';
1907
  }
1908
 
1909
  var rtmedia_plupload_file = '<li class="plupload_file ui-state-default plupload_queue_li" id="' + file.id + '" ' + title + '>';
2414
  jQuery( input_file_el ).click();
2415
  file_dialog_open = false;
2416
  }
2417
+ $(this).blur();
2418
  } );
2419
 
2420
  var form_html = jQuery( "."+comment_media_wrapper+widget_id );
2531
 
2532
  // Show/create text box to edit media title
2533
  if ( jQuery( rtm_file_title_input ).length === 0 ) {
2534
+ jQuery( rtm_file_label ).parent( '.plupload_file_name' ).prepend( '<div id="' + rtm_file_title_wrapper_id + '" class="rtm-upload-edit-title-wrapper"><label>' + rtmedia_edit_media_info_upload.title + '</label><input type="text" class="rtm-upload-edit-title" id="' + rtm_file_title_id + '" value="' + file.title + '" style="width: 75%;" /></div><div id="' + rtm_file_desc_wrapper_id + '" class="rtm-upload-edit-desc-wrapper"><label>' + rtmedia_edit_media_info_upload.description + '</label><textarea class="rtm-upload-edit-desc" id="' + rtm_file_desc_id + '"></textarea></div><span id="' + rtm_file_save_id + '" title="Save Change" class="dashicons dashicons-yes"></span>' );
2535
  } else {
2536
  jQuery( rtm_file_title_wrapper ).show();
2537
  jQuery( rtm_file_desc_wrapper ).show();
app/assets/js/rtMedia.js CHANGED
@@ -11,6 +11,10 @@ function apply_rtMagnificPopup( selector ) {
11
  }
12
  if ( typeof( rtmedia_lightbox_enabled ) != 'undefined' && rtmedia_lightbox_enabled == '1' ) { // If lightbox is enabled.
13
 
 
 
 
 
14
  if ( $( '.activity-item .rtmedia-activity-container .rtmedia-list-item > a' ).siblings( 'p' ).children( 'a' ).length > 0 ) {
15
  $( '.activity-item .rtmedia-activity-container .rtmedia-list-item > a' ).siblings( 'p' ).children( 'a' ).addClass( 'no-popup' );
16
  }
@@ -52,6 +56,13 @@ function apply_rtMagnificPopup( selector ) {
52
  if ( ( li.is( ':nth-last-child(2)' ) || li.is( ':last-child' ) ) && li.find( 'a' ).hasClass('rtmedia-list-item-a') ) { // If its last second media
53
  var last_li = li.next();
54
  if ( jQuery( '#rtMedia-galary-next' ).css( 'display' ) == 'block' ) { // If more medias are available
 
 
 
 
 
 
 
55
  jQuery( '#rtMedia-galary-next' ).click(); // Load more
56
  }
57
  }
@@ -143,6 +154,21 @@ function apply_rtMagnificPopup( selector ) {
143
  },
144
  close: function( e ) {
145
  //Console.log(e);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  rtmedia_single_page_popup_close();
147
  },
148
  BeforeChange: function( e ) {
@@ -1270,10 +1296,31 @@ function rtm_upload_terms_activity() {
1270
  rtp_display_terms_warning( selector, rtmedia_upload_terms_check_terms_message );
1271
  }
1272
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
1273
  }
1274
  }
1275
 
1276
  jQuery( document ).ready( function () {
1277
  // Call function when document loaded.
1278
  rtm_upload_terms_activity();
 
 
 
 
 
 
 
1279
  });
 
11
  }
12
  if ( typeof( rtmedia_lightbox_enabled ) != 'undefined' && rtmedia_lightbox_enabled == '1' ) { // If lightbox is enabled.
13
 
14
+ var old_gallery_media;
15
+ var current_page;
16
+ var more_media_loaded = false;
17
+
18
  if ( $( '.activity-item .rtmedia-activity-container .rtmedia-list-item > a' ).siblings( 'p' ).children( 'a' ).length > 0 ) {
19
  $( '.activity-item .rtmedia-activity-container .rtmedia-list-item > a' ).siblings( 'p' ).children( 'a' ).addClass( 'no-popup' );
20
  }
56
  if ( ( li.is( ':nth-last-child(2)' ) || li.is( ':last-child' ) ) && li.find( 'a' ).hasClass('rtmedia-list-item-a') ) { // If its last second media
57
  var last_li = li.next();
58
  if ( jQuery( '#rtMedia-galary-next' ).css( 'display' ) == 'block' ) { // If more medias are available
59
+
60
+ if ( ! more_media_loaded ) {
61
+ old_gallery_media = mfp.ev.children();
62
+ more_media_loaded = true;
63
+ current_page = nextpage;
64
+ }
65
+
66
  jQuery( '#rtMedia-galary-next' ).click(); // Load more
67
  }
68
  }
154
  },
155
  close: function( e ) {
156
  //Console.log(e);
157
+
158
+ //If more media is loaded in lighbox then remove them set nextpage to default one.
159
+ if ( more_media_loaded ) {
160
+
161
+ mfp.ev.empty();
162
+ mfp.ev.append( old_gallery_media );
163
+
164
+ nextpage = current_page;
165
+ more_media_loaded = false;
166
+
167
+ if ( nextpage > 1 ) {
168
+ jQuery( '#rtMedia-galary-next' ).show();
169
+ }
170
+ }
171
+
172
  rtmedia_single_page_popup_close();
173
  },
174
  BeforeChange: function( e ) {
1296
  rtp_display_terms_warning( selector, rtmedia_upload_terms_check_terms_message );
1297
  }
1298
  });
1299
+
1300
+ var bp_legacy_form = jQuery( '#whats-new-form' );
1301
+
1302
+ // Re-enable hidden inputs disabled in the activity post form.
1303
+ if ( bp_legacy_form.length > 0 ) {
1304
+ // Add upload terms element selector to work when direct upload is enabled.
1305
+ jQuery( '#whats-new-form, #rtmedia_upload_terms_conditions' ).on( 'click', function ( event ) {
1306
+ var hidden_fields = bp_legacy_form.find( 'input:hidden' );
1307
+ hidden_fields.each( function() {
1308
+ jQuery(this).prop( 'disabled', false );
1309
+ } );
1310
+ } );
1311
+ }
1312
  }
1313
  }
1314
 
1315
  jQuery( document ).ready( function () {
1316
  // Call function when document loaded.
1317
  rtm_upload_terms_activity();
1318
+
1319
+ // Avoid Lightbox conflict due to class has-sidebar in theme 2017 v2.1.
1320
+ if( jQuery( 'body' ).hasClass( 'has-sidebar' ) && 0 === jQuery( '#secondary' ).length ) {
1321
+ if ( jQuery( '.rtmedia-single-container' ).length || jQuery( '.rtmedia-container' ).length ) {
1322
+ jQuery( 'body' ).removeClass( 'has-sidebar' );
1323
+ }
1324
+ }
1325
  });
1326
+
app/assets/js/rtmedia.min.js CHANGED
@@ -3,5 +3,5 @@
3
  * @package rtMedia
4
  */
5
 
6
- function apply_rtMagnificPopup(a){jQuery("document").ready(function(b){var c="";c="undefined"==typeof rtmedia_load_more?"Loading media":rtmedia_load_more,"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&(b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").length>0&&b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").addClass("no-popup"),rtMagnificPopup=jQuery(a).magnificPopup({delegate:"a:not(.no-popup, .mejs-time-slider, .mejs-volume-slider, .mejs-horizontal-volume-slider)",type:"ajax",fixedContentPos:!0,fixedBgPos:!0,tLoading:c+" #%curr%...",mainClass:"mfp-img-mobile",preload:[1,3],closeOnBgClick:!0,gallery:{enabled:!0,navigateByImgClick:!0,arrowMarkup:"",preload:[0,1]},image:{tError:'<a href="%url%">The image #%curr%</a> could not be loaded.',titleSrc:function(a){return a.el.attr("title")+"<small>by Marsel Van Oosten</small>"}},callbacks:{ajaxContentAdded:function(){a=jQuery.magnificPopup.instance,1===jQuery(a.items).size()&&jQuery(".mfp-arrow").remove();var a=jQuery.magnificPopup.instance,c=a.currItem.el,d=c.parent();if(d.is("li")||(d=d.parent()),(d.is(":nth-last-child(2)")||d.is(":last-child"))&&d.find("a").hasClass("rtmedia-list-item-a")){d.next();"block"==jQuery("#rtMedia-galary-next").css("display")&&jQuery("#rtMedia-galary-next").click()}var e=a.items.length;if(a.index==e-1&&!d.is(":last-child"))return void c.click();var f={};"undefined"!=typeof _wpmejsSettings&&(f.pluginPath=_wpmejsSettings.pluginPath);var g=jQuery(".rtmedia-container .rtmedia-single-meta").height(),h=!1;void 0!==a&&void 0!==a.probablyMobile&&1==a.probablyMobile&&(h=!0),b(".mfp-content .rtmedia-single-media .wp-audio-shortcode,.mfp-content .rtmedia-single-media .wp-video-shortcode,.mfp-content .rtmedia-single-media .bp_media_content video").attr("autoplay",!0),h&&b(".mfp-content .rtmedia-single-media .wp-video-shortcode,.mfp-content .rtmedia-single-media .bp_media_content video").attr("muted",!1),b(".mfp-content .rtmedia-single-media .wp-audio-shortcode,.mfp-content .rtmedia-single-media .wp-video-shortcode,.mfp-content .rtmedia-single-media .bp_media_content video").mediaelementplayer({classPrefix:"mejs-",defaultVideoWidth:480,hideVolumeOnTouchDevices:!1,features:["playpause","progress","current","volume","fullscreen"],defaultVideoHeight:270,alwaysShowControls:h,enableAutosize:!0,clickToPlayPause:!0,videoHeight:-1,success:function(a,c){a.addEventListener("loadeddata",function(c){var d=b(a).height(),e=b(window).height(),f=jQuery("div.rtm-ltb-action-container").height(),f=f+50,h=g-f;d>e&&jQuery(".rtmedia-container #rtmedia-single-media-container .mejs-container").attr("style","height:"+h+"px !important; transition:0.2s")},!1),h&&b(a).hasClass("wp-video-shortcode")?jQuery("body").on("touchstart",".mejs-overlay-button",function(b){a.paused?a.play():a.pause()}):a.pause()}}),b(".mfp-content .mejs-audio .mejs-controls").css("position","relative"),rtMediaHook.call("rtmedia_js_popup_after_content_added",[]),"undefined"!=typeof bp&&void 0!==bp.mentions&&void 0!==bp.mentions.users&&(b("#atwho-container #atwho-ground-comment_content").remove(),b("#comment_content").bp_mentions(bp.mentions.users)),rtmedia_reset_video_and_audio_for_popup(),apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container")},open:function(){var a=jQuery(".mfp-bg"),b=jQuery(".mfp-wrap");a.height(a.height()+b.height())},close:function(a){rtmedia_single_page_popup_close()},BeforeChange:function(a){}}})),jQuery(document).ajaxComplete(function(){jQuery("[id^=imgedit-leaving]").filter(function(){var a=jQuery(this).text();jQuery(this).text(a.replace("OK","Save"))})})})}function rtmedia_init_action_dropdown(a){var b,c;jQuery(a+" .click-nav > span,"+a+" .click-nav > div").toggleClass("no-js js"),jQuery(a+" .click-nav .js ul").hide(),jQuery(a+" .click-nav .clicker").click(function(a){b=jQuery("#rtm-media-options .click-nav .clicker").next("ul"),c=jQuery(this).next("ul"),jQuery.each(b,function(a,b){jQuery(b).html()!=c.html()&&jQuery(b).hide()}),jQuery(c).toggle(),a.stopPropagation()})}function bp_media_create_element(a){return!1}function rtmedia_version_compare(a,b){if(typeof a+typeof b!="stringstring")return!1;for(var c=a.split("."),d=b.split("."),e=0,f=Math.max(c.length,d.length);e<f;e++){if(c[e]&&!d[e]&&parseInt(c[e])>0||parseInt(c[e])>parseInt(d[e]))return!0;if(d[e]&&!c[e]&&parseInt(d[e])>0||parseInt(c[e])<parseInt(d[e]))return!1}return!0}function rtm_is_element_exist(a){return jQuery(a).length>0}function rtm_masonry_reload(a){setTimeout(function(){a.masonry("reload")},250)}function rtm_search_media_text_validation(){""===jQuery("#media_search_input").val()?jQuery("#media_search").css("cursor","not-allowed"):jQuery("#media_search").css("cursor","pointer")}function rtmediaGetParameterByName(a){a=a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var b=new RegExp("[\\?&]"+a+"=([^&#]*)"),c=b.exec(location.search);return null==c?"":decodeURIComponent(c[1].replace(/\+/g," "))}function rtmedia_single_media_alert_message(a,b,c){var d="rtmedia-success";"warning"==b&&(d="rtmedia-warning");var e=!1;jQuery(".rtmedia-message-container").each(function(a,b){return b=jQuery(b),c&&b.hasClass("rtmedia-empty-comment-error-class")?(b.remove(),e=!0,!1):void 0!==c||b.hasClass("rtmedia-empty-comment-error-class")?void 0:(b.remove(),e=!0,!1)});var f=jQuery("<div>",{title:"Click to dismiss",class:"rtmedia-message-container"+(c?" rtmedia-empty-comment-error-class":""),style:"margin:1em 0;"}),g=jQuery("<span>",{class:d});g.html(a),g.appendTo(f);var h;c?(h=jQuery("#rt_media_comment_form"),jQuery("#comment_content").focus()):void 0===c&&(h=jQuery(".rtmedia-single-media .rtmedia-media"),h.css("opacity","0.2")),h.after(f),e&&(g.css({border:"2px solid #884646"}),setTimeout(function(){g.css({border:"none"})},500)),setTimeout(function(){f.remove(),void 0===c&&h.css("opacity","1")},3e3),f.click(function(){f.remove(),void 0===c&&h.css("opacity","1")})}function rtmedia_gallery_action_alert_message(a,b){var c="rtmedia-success";"warning"==b&&(c="rtmedia-warning");jQuery("body").append('<div class="rtmedia-gallery-alert-container"> </div>'),jQuery(".rtmedia-gallery-alert-container").append("<div class='rtmedia-gallery-message-box'><span class='"+c+"'>"+a+" </span></div>"),setTimeout(function(){jQuery(".rtmedia-gallery-alert-container").remove()},3e3),jQuery(".rtmedia-gallery-message-box").click(function(){jQuery(".rtmedia-gallery-alert-container").remove()})}function rtmedia_activity_masonry(){jQuery("#activity-stream .rtmedia-activity-container .rtmedia-list").masonry({itemSelector:".rtmedia-list-item",gutter:7});var a=0,b=setInterval(function(){a+=1,5===a&&clearInterval(b),jQuery.each(jQuery(".rtmedia-activity-container .rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())}),rtm_masonry_reload(jQuery("#activity-stream .rtmedia-activity-container .rtmedia-list"))},1e3)}function get_parameter(a,b){if(!a)return!1;b||(b=window.location.href);var a=a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]"),c=a+"=([^&#]*)",d=new RegExp(c),e=d.exec(b);return null!==e&&e[1]}function rtm_upload_terms_activity(){jQuery("#rtmedia_upload_terms_conditions").length>0&&jQuery("#bp-nouveau-activity-form").on("click","#aw-whats-new-submit",function(a){var b=jQuery("#whats-new-form"),c=b.find("#rtmedia_upload_terms_conditions");if(0!==c.length&&!1===c.prop("checked")&&0===b.find("#message").length){a.preventDefault();var d=b.find(".rtmedia-upload-terms");rtp_display_terms_warning(d,rtmedia_upload_terms_check_terms_message)}})}!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h=function(){},i=!!window.jQuery,j=a(window),k=function(a,c){b.ev.on("mfp"+a+".mfp",c)},l=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},m=function(c,d){b.ev.triggerHandler("mfp"+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},n=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},o=function(){a.magnificPopup.instance||(b=new h,b.init(),a.magnificPopup.instance=b)},p=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};h.prototype={constructor:h,init:function(){var c=navigator.appVersion;b.isIE7=-1!==c.indexOf("MSIE 7."),b.isIE8=-1!==c.indexOf("MSIE 8."),b.isLowIE=b.isIE7||b.isIE8,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=p(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(!1===c.isObj){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",c.mainEl&&c.mainEl.length?b.ev=c.mainEl.eq(0):b.ev=d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=l("bg").on("click.mfp",function(){b.close()}),b.wrap=l("wrap").attr("tabindex",-1).on("click.mfp",function(a){b._checkIfClose(a.target)&&b.close()}),b.container=l("container",b.wrap)),b.contentContainer=l("content"),b.st.preloader&&(b.preloader=l("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var o=i[e];o=o.charAt(0).toUpperCase()+o.slice(1),b["init"+o].call(b)}m("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(k("MarkupParse",function(a,b,c,d){c.close_replaceWith=n(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(n())),b.st.alignTop&&(f+=" mfp-align-top"),b.fixedContentPos?b.wrap.css({overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.st.overflowY}):b.wrap.css({top:j.scrollTop(),position:"absolute"}),(!1===b.st.fixedBgPos||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup.mfp",function(a){27===a.keyCode&&b.close()}),j.on("resize.mfp",function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var p=b.wH=j.height(),q={};if(b.fixedContentPos&&b._hasScrollBar(p)){var r=b._getScrollbarSize();r&&(q.marginRight=r)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):q.overflow="hidden");var s=b.st.mainClass;return b.isIE7&&(s+=" mfp-ie7"),s&&b._addClassToMFP(s),b.updateItemHTML(),m("BuildControls"),a("html").css(q),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP("mfp-ready"),b._setFocus()):b.bgOverlay.addClass("mfp-ready"),d.on("focusin.mfp",b._onFocusIn)},16),b.isOpen=!0,b.updateSize(p),m("Open"),c},close:function(){b.isOpen&&(m("BeforeClose"),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP("mfp-removing"),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){m("Close");var c="mfp-removing mfp-ready ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup.mfp focusin.mfp"),b.ev.off(".mfp"),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&!0!==b.currTemplate[b.currItem.type]||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,m("AfterClose")},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||j.height();b.fixedContentPos||b.wrap.css("height",b.wH),m("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(m("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=!!b.st[d]&&b.st[d].markup;m("FirstMarkupParse",f),b.currTemplate[d]=!f||a(f)}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,m("Change",c),e=c.type,b.container.prepend(b.contentContainer),m("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&!0===b.currTemplate[c]?b.content.find(".mfp-close").length||b.content.append(n()):b.content=a:b.content="",m("BeforeAppend"),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,m("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){if((void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick)||2!==c.which&&!c.ctrlKey&&!c.metaKey){var f=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(f)if(a.isFunction(f)){if(!f.call(b))return!0}else if(j.width()<f)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};m("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass("mfp-prevent-close")){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||j.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){if(c.target!==b.wrap[0]&&!a.contains(b.wrap[0],c.target))return b._setFocus(),!1},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),m("MarkupParse",[b,c,d]),a.each(c,function(a,c){if(void 0===c||!1===c)return!0;if(e=a.split("_"),e.length>1){var d=b.find(".mfp-"+e[0]);if(d.length>0){var f=e[1];"replaceWith"===f?d[0]!==c[0]&&d.replaceWith(c):"img"===f?d.is("img")?d.attr("src",c):d.replaceWith('<img src="'+c+'" class="'+d.attr("class")+'" />'):d.attr(e[1],c)}}else b.find(".mfp-"+a).html(c)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:h.prototype,modules:[],open:function(b,c){return o(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&times;</button>',tClose:"Close (Esc)",tLoading:"Loading..."}},a.fn.magnificPopup=function(c){o();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=i?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),i?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var q,r,s,t=function(){s&&(r.after(s.addClass(q)).detach(),s=null)};a.magnificPopup.registerModule("inline",{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push("inline"),k("Close.inline",function(){t()})},getInline:function(c,d){if(t(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(r||(q=e.hiddenClass,r=l(q),q="mfp-"+q),s=f.after(r).detach().removeClass(q)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var u,v=function(){u&&a(document.body).removeClass(u)},w=function(){v(),b.req&&b.req.abort()};a.magnificPopup.registerModule("ajax",{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push("ajax"),u=b.st.ajax.cursor,k("Close.ajax",w),k("BeforeChange.ajax",w)},getAjax:function(c){u&&a(document.body).addClass(u),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};m("ParseAjax",g),b.appendContent(a(g.data),"ajax"),c.finished=!0,v(),b._setFocus(),setTimeout(function(){b.wrap.addClass("mfp-ready")},16),b.updateStatus("ready"),m("AjaxContentAdded")},error:function(){v(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var x,y=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),k("Open"+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),k("Close"+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),j.off("resize.mfp")}),k("Resize"+d,b.resizeImage),b.isLowIE&&k("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,x&&clearInterval(x),a.isCheckingImgSize=!1,m("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){x&&clearInterval(x),x=setInterval(function(){if(d.naturalWidth>0)return void b._onImageHasSize(a);c>200&&clearInterval(x),c++,3===c?e(10):40===c?e(50):100===c&&e(500)},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,m("ImageLoadComplete")):(e++,e<200?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:y(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(x&&clearInterval(x),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var z,A=function(){return void 0===z&&(z=void 0!==document.createElement("p").style.MozTransform),z};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,h=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},i=function(){b.content.css("visibility","visible")};k("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),!(a=b._getItemToZoom()))return void i();f=h(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){i(),setTimeout(function(){f.remove(),a=f=null,m("ZoomAnimationEnded")},16)},g)},16)}}),k("BeforeClose"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(!(a=b._getItemToZoom()))return;f=h(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),k("Close"+d,function(){b._allowZoom()&&(i(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return!!b.currItem.hasSize&&b.currItem.img},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(i?d.innerHeight():d[0].offsetHeight)-g-f};return A()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});var B=function(a){if(b.currTemplate.iframe){var c=b.currTemplate.iframe.find("iframe");c.length&&(a||(c[0].src="//about:blank"),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule("iframe",{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push("iframe"),k("BeforeChange",function(a,b,c){b!==c&&("iframe"===b?B():"iframe"===c&&B(!0))}),k("Close.iframe",function(){B()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){if(e.indexOf(this.index)>-1)return this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var C=function(a){var c=b.items.length;return a>c-1?a-c:a<0?c+a:a},D=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);if(b.direction=!0,!c||!c.enabled)return!1;f+=" mfp-gallery",k("Open"+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){if(b.items.length>1)return b.next(),!1}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),k("UpdateStatus"+e,function(a,c){c.text&&(c.text=D(c.text,b.currItem.index,b.items.length))}),k("MarkupParse"+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?D(c.tCounter,f.index,g):""}),k("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass("mfp-prevent-close"),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass("mfp-prevent-close"),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(l("b",e[0],!1,!0),l("a",e[0],!1,!0),l("b",f[0],!1,!0),l("a",f[0],!1,!0)),b.container.append(e.add(f))}}),k("Change"+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),k("Close"+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})},next:function(){b.direction=!0,b.index=C(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=C(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=C(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),m("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,m("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});a.magnificPopup.registerModule("retina",{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(k("ImageHasSize.retina",function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),k("ElementParse.retina",function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b="ontouchstart"in window,c=function(){j.off("touchmove"+d+" touchend"+d)},d=".mfpFastClick";a.fn.mfpFastClick=function(e){return a(this).each(function(){var f,g=a(this);if(b){var h,i,k,l,m,n;g.on("touchstart"+d,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],i=m.clientX,k=m.clientY,j.on("touchmove"+d,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-i)>10||Math.abs(m.clientY-k)>10)&&(l=!0,c())}).on("touchend"+d,function(a){c(),l||n>1||(f=!0,a.preventDefault(),clearTimeout(h),h=setTimeout(function(){f=!1},1e3),e())})})}g.on("click"+d,function(){f||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+d+" click"+d),b&&j.off("touchmove"+d+" touchend"+d)}}(),o()}),"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b}),function(a,b,c,d){var e={init:function(b,c){var d=this;d.elem=c,d.$elem=a(c),d.options=a.extend({},a.fn.rtTab.options,b),d.rtTabs()},rtTabs:function(){var c=this,d=c.options.activeTab;if(c.$elem.find("li:nth-child("+d+")").addClass("active"),c.rtTabContent(activeTabContent="yes"),c.rtClick(),!0==("false"!==c.$elem.attr("data-hash"))){var e=b.location.hash;e&&c.$elem.find("li").find('a[href="'+e+'"]').trigger("click"),a(b).on("hashchange",function(){var a=b.location.hash;c.$elem.find("li").find('a[href="'+a+'"]').trigger("click")})}},rtClick:function(){var c=this,d=c.$elem.find("li");d.find("a").on("click",function(e){e.preventDefault(),d.removeClass("active"),c.rtTabContent(),a(this).parent().addClass("active");var f=a(this).attr("href");if(a(f).removeClass("hide"),1==("false"!==c.$elem.attr("data-hash"))){var g=a(b).scrollTop();location.hash=a(this).attr("href"),a(b).scrollTop(g)}"function"==typeof c.options.onComplete&&c.options.onComplete.apply(c.elem,arguments)})},rtTabContent:function(b){this.$elem.find("li").find("a").each(function(){var c=a(this),d=c.attr("href");"yes"===b?c.parent().hasClass("active")||a(d).addClass("hide"):a(d).addClass("hide")})}};a.fn.rtTab=function(b){return this.each(function(){var c=Object.create(e);c.init(b,this),a.data(this,"rtTab",c)})},a.fn.rtTab.options={activeTab:1,onComplete:null}}(jQuery,window,document);var rtMagnificPopup,rtm_masonry_container,comment_media=!1,rtMediaHook={hooks:[],is_break:!1,register:function(a,b){void 0===rtMediaHook.hooks[a]&&(rtMediaHook.hooks[a]=[]),rtMediaHook.hooks[a].push(b)},call:function(a,arguments){if(void 0!==rtMediaHook.hooks[a])for(i=0;i<rtMediaHook.hooks[a].length;++i)if(1!=rtMediaHook.hooks[a][i](arguments))return rtMediaHook.is_break=!0,!1;return!0}};jQuery("document").ready(function(a){function b(){if(jQuery("#rtmedia-media-view-form").length>0){var a=jQuery("#rtmedia-media-view-form").attr("action");jQuery.post(a,{},function(a){})}}function c(){var a=jQuery.magnificPopup.instance,b=a.probablyMobile,c=e("rtmedia-touch-swipe-tooltip");b&&""===c?(jQuery("#mobile-swipe-overlay").show(),jQuery("#mobile-swipe-overlay").on("click",function(a){d("rtmedia-touch-swipe-tooltip",!0,365),jQuery(this).hide(),jQuery("#rtmedia-single-media-container .mejs-playpause-button").trigger("click")}),jQuery("#mobile-swipe-overlay").swipe({swipe:function(a,b,c,e,f,g){d("rtmedia-touch-swipe-tooltip",!0,365),jQuery("#mobile-swipe-overlay").hide(),jQuery("#rtmedia-single-media-container .mejs-playpause-button").trigger("click")},threshold:0})):jQuery("#rtmedia-single-media-container .mejs-playpause-button").trigger("click"),jQuery(".mfp-arrow-right").on("click",function(b){a.next()}),jQuery(".mfp-arrow-left").on("click",function(b){a.prev()}),jQuery(".mfp-content .rtmedia-media").swipe({swipeLeft:function(b,c,d,e,f){a.next()},
7
- swipeRight:function(b,c,d,e,f){a.prev()},threshold:0})}function d(a,b,c){var d=new Date;d.setTime(d.getTime()+24*c*60*60*1e3);var e="expires="+d.toUTCString();document.cookie=a+"="+b+";"+e+";path=/"}function e(a){for(var b=a+"=",c=document.cookie.split(";"),d=0;d<c.length;d++){for(var e=c[d];" "==e.charAt(0);)e=e.substring(1);if(0==e.indexOf(b))return e.substring(b.length,e.length)}return""}function f(){jQuery(".mfp-arrow-right").hide(),jQuery(".mfp-arrow-left").hide(),jQuery(document).unbind("keydown")}function g(){rtmedia_disable_popup_navigation("#comment_content")}function h(){jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()})}jQuery(document).ajaxComplete(function(a,b,c){if("legacy"!==bp_template_pack&&bp_template_pack){var d=get_parameter("action",c.data);"activity_filter"!==d&&"post_update"!==d&&"get_single_activity_content"!==d&&"activity_get_older_updates"!==d||"undefined"==typeof rtmedia_masonry_layout||"true"!==rtmedia_masonry_layout||"undefined"==typeof rtmedia_masonry_layout_activity||"true"!==rtmedia_masonry_layout_activity?"activity_filter"!==d&&"post_update"!==d&&"get_single_activity_content"!==d&&"activity_get_older_updates"!==d||setTimeout(function(){apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),rtmedia_activity_stream_comment_media()},1e3):setTimeout(function(){apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),rtmedia_activity_masonry(),rtmedia_activity_stream_comment_media()},1e3)}}),jQuery(".rtmedia-uploader-div").css({opacity:"1",display:"block",visibility:"visible"}),jQuery(" #whats-new-options ").css({opacity:"1"}),void 0!==a.fn.rtTab&&a(".rtm-tabs").rtTab(),jQuery(".rtmedia-modal-link").length>0&&a(".rtmedia-modal-link").magnificPopup({type:"inline",midClick:!0,closeBtnInside:!0}),a("#rt_media_comment_form").submit(function(b){return""!=a.trim(a("#comment_content").val())||(0==jQuery("#rtmedia-single-media-container").length?rtmedia_gallery_action_alert_message(rtmedia_empty_comment_msg,"warning"):rtmedia_single_media_alert_message(rtmedia_empty_comment_msg,"warning"),!1)}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||void 0===b.data||void 0===b.data.action)return!0}catch(a){return!0}if("activity_get_older_updates"==b.data.action){var d=b.success;a.success=function(a){"function"==typeof d&&d(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}else if("get_single_activity_content"==b.data.action){var d=b.success;a.success=function(a){"function"==typeof d&&d(a),setTimeout(function(){apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),jQuery("ul.activity-list li.rtmedia_update:first-child .wp-audio-shortcode, ul.activity-list li.rtmedia_update:first-child .wp-video-shortcode").mediaelementplayer({classPrefix:"mejs-",defaultVideoWidth:480,defaultVideoHeight:270})},900)}}}),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||void 0===b.data||void 0===b.data.action)return!0}catch(a){return!0}if("activity_get_older_updates"==b.data.action){var d=b.success;a.success=function(a){"function"==typeof d&&d(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),jQuery("ul.activity-list li.rtmedia_update div.rtmedia-item-thumbnail > audio.wp-audio-shortcode, ul.activity-list li.rtmedia_update div.rtmedia-item-thumbnail > video.wp-video-shortcode").mediaelementplayer({classPrefix:"mejs-",defaultVideoWidth:480,defaultVideoHeight:270}),setTimeout(function(){rtmedia_activity_stream_comment_media()},900),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}}),jQuery(".rtmedia-container").on("click",".select-all",function(a){jQuery(this).toggleClass("unselect-all").toggleClass("select-all"),jQuery(this).attr("title",rtmedia_unselect_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!0)}),jQuery(".rtmedia-list-item").addClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".unselect-all",function(a){jQuery(this).toggleClass("select-all").toggleClass("unselect-all"),jQuery(this).attr("title",rtmedia_select_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!1)}),jQuery(".rtmedia-list-item").removeClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".rtmedia-move",function(a){jQuery(".rtmedia-delete-container").slideUp(),jQuery(".rtmedia-move-container").slideToggle()}),jQuery("#rtmedia-create-album-modal").on("click","#rtmedia_create_new_album",function(b){if($albumname=jQuery("<span/>").text(jQuery.trim(jQuery("#rtmedia_album_name").val())).html(),$album_description=jQuery("#rtmedia_album_description"),$context=jQuery.trim(jQuery("#rtmedia_album_context").val()),$context_id=jQuery.trim(jQuery("#rtmedia_album_context_id").val()),$privacy=jQuery.trim(jQuery("#rtmedia_select_album_privacy").val()),$create_album_nonce=jQuery.trim(jQuery("#rtmedia_create_album_nonce").val()),""!=$albumname){var c={action:"rtmedia_create_album",name:$albumname,description:$album_description.val(),context:$context,context_id:$context_id,create_album_nonce:$create_album_nonce};""!==$privacy&&(c.privacy=$privacy),a("#rtmedia_create_new_album").attr("disabled","disabled");var d=a("#rtmedia_create_new_album").html();a("#rtmedia_create_new_album").prepend("<img src='"+rMedia_loading_file+"' />"),jQuery.post(rtmedia_ajax_url,c,function(b){if(void 0!==b.album){b=jQuery.trim(b.album);var c=!0;$album_description.val(""),a("#rtmedia_album_name").focus(),jQuery(".rtmedia-user-album-list").each(function(){if(jQuery(this).children("optgroup").each(function(){if(jQuery(this).attr("value")===$context)return c=!1,void jQuery(this).append('<option value="'+b+'">'+$albumname+"</option>")}),c){var a=$context.charAt(0).toUpperCase()+$context.slice(1)+" "+rtmedia_main_js_strings.rtmedia_albums,d='<optgroup value="'+$context+'" label="'+a+'"><option value="'+b+'">'+$albumname+"</option></optgroup>";jQuery(this).append(d)}}),jQuery('select.rtmedia-user-album-list option[value="'+b+'"]').prop("selected",!0),jQuery(".rtmedia-create-new-album-container").slideToggle(),jQuery("#rtmedia_album_name").val(""),jQuery("#rtmedia-create-album-modal").append("<div class='rtmedia-success rtmedia-create-album-alert'><b>"+$albumname+"</b>"+rtmedia_album_created_msg+"</div>"),setTimeout(function(){jQuery(".rtmedia-create-album-alert").remove()},4e3),setTimeout(function(){galleryObj.reloadView(),jQuery(".close-reveal-modal").click()},2e3)}else void 0!==b.error?rtmedia_gallery_action_alert_message(b.error,"warning"):rtmedia_gallery_action_alert_message(rtmedia_something_wrong_msg,"warning");a("#rtmedia_create_new_album").removeAttr("disabled"),a("#rtmedia_create_new_album").html(d)})}else rtmedia_gallery_action_alert_message(rtmedia_empty_album_name_msg,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_delete_confirmation)&&jQuery(this).closest("form").attr("action","../../../"+rtmedia_media_slug+"/delete").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-move-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_move_confirmation)&&jQuery(this).closest("form").attr("action","").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery("#buddypress").on("change",".rtm-activity-privacy-opt",function(){var a=jQuery(this).attr("id");a=a.split("-"),a=a[a.length-1];var b=this;data={activity_id:a,privacy:jQuery(this).val(),nonce:jQuery("#rtmedia_activity_privacy_nonce").val(),action:"rtm_change_activity_privacy"},jQuery.post(ajaxurl,data,function(a){var c="",d="";"true"==a?(c=rtmedia_main_js_strings.privacy_update_success,d="success"):(c=rtmedia_main_js_strings.privacy_update_error,d="fail"),jQuery(b).after('<p class="rtm-ac-privacy-updated '+d+'">'+c+"</p>"),setTimeout(function(){jQuery(b).siblings(".rtm-ac-privacy-updated").remove()},2e3)})}),jQuery(".media_search_input").on("keyup",function(){rtm_search_media_text_validation()}),b(),rtMediaHook.register("rtmedia_js_popup_after_content_added",function(){b(),h(),mfp=jQuery.magnificPopup.instance,jQuery(mfp.items).size()>1&&0==comment_media?c():f(),g(),rtmedia_disable_popup_navigation_comment_media_focus();var d=a(window).height();jQuery(".rtm-lightbox-container .mejs-video").css({height:.8*d,"over-flow":"hidden"}),jQuery(".mfp-content .rtmedia-media").css({"max-height":.87*d,"over-flow":"hidden"}),rtmedia_init_action_dropdown(".rtm-lightbox-container .rtmedia-actions"),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").shorten({showChars:130});var e=a(".rtm-gallery-title"),i="";""!=(i=a.isEmptyObject(e)?a("#subnav.item-list-tabs li.selected ").html():e.html())&&a(".rtm-ltb-gallery-title .ltb-title").html(i);var j=a("#subnav.item-list-tabs li.selected span").html();return a("li.total").html(j),!0});var i=jQuery("#drag-drop-area"),j=jQuery("#whats-new");i.html();jQuery("#rtmedia-upload-container").after("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&jQuery("#whats-new-textarea").append("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),jQuery(document).on("dragover",function(a){a.preventDefault(),a.target!=this&&(jQuery("#rtm-media-gallery-uploader").show(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&j.addClass("rtm-drag-drop-active"),i.addClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").show())}).on("dragleave",function(a){if(a.preventDefault(),0!=a.originalEvent.pageX&&0!=a.originalEvent.pageY)return!1;"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(j.removeClass("rtm-drag-drop-active"),j.removeAttr("style")),i.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}).on("drop",function(a){a.preventDefault(),jQuery(".bp-suggestions").focus(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(j.removeClass("rtm-drag-drop-active"),j.removeAttr("style")),i.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-album",function(a){a.preventDefault(),confirm(rtmedia_album_delete_confirmation)&&jQuery(this).closest("form").submit()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()}),rtmedia_init_action_dropdown(""),a(document).click(function(){a(".click-nav ul").is(":visible")&&a(".click-nav ul",this).hide()}),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").length>0&&a(".rtm-more").shorten({showChars:200}),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&"undefined"!=typeof rtmedia_masonry_layout_activity&&"true"==rtmedia_masonry_layout_activity&&rtmedia_activity_masonry(),jQuery(document).ajaxComplete(function(a,b,c){var d=get_parameter("action",c.data);"post_update"!==d&&"get_single_activity_content"!==d&&"activity_get_older_updates"!==d||"undefined"==typeof rtmedia_masonry_layout||"true"!=rtmedia_masonry_layout||"undefined"==typeof rtmedia_masonry_layout_activity||"true"!=rtmedia_masonry_layout_activity||rtmedia_activity_masonry()}),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&(rtm_masonry_container=jQuery(".rtmedia-container .rtmedia-list"),rtm_masonry_container.masonry({itemSelector:".rtmedia-list-item"}),setInterval(function(){jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())}),rtm_masonry_reload(rtm_masonry_container)},1e3),jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())})),jQuery(".rtm-uploader-tabs").length>0&&jQuery(".rtm-uploader-tabs li").click(function(a){jQuery(this).hasClass("active")||(jQuery(this).siblings().removeClass("active"),jQuery(this).parents(".rtm-uploader-tabs").siblings().hide(),class_name=jQuery(this).attr("class"),jQuery(this).parents(".rtm-uploader-tabs").siblings('[data-id="'+class_name+'"]').show(),jQuery(this).addClass("active"),"rtm-upload-tab"!=class_name?jQuery("div.moxie-shim").hide():jQuery("div.moxie-shim").show())}),jQuery(".rtmedia-container").on("click",".rtm-delete-media",function(a){a.preventDefault();var b="Are you sure you want to delete this media?";if("undefined"!=typeof rtmedia_media_delete_confirmation&&(b=rtmedia_media_delete_confirmation),confirm(b)){var c=jQuery(this).closest("li"),d=jQuery("#rtmedia_media_delete_nonce").val(),e={action:"delete_uploaded_media",nonce:d,media_id:c.attr("id")};jQuery.ajax({url:ajaxurl,type:"post",data:e,success:function(a){"1"==a?(rtmedia_gallery_action_alert_message(rtmedia_main_js_strings.file_delete_success,"success"),c.remove(),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container)):rtmedia_gallery_action_alert_message(rtmedia_file_not_deleted,"warning")}})}})}),function(a){a.fn.shorten=function(b){"use strict";var c={showChars:100,minHideChars:10,ellipsesText:"...",moreText:rtmedia_read_more,lessText:rtmedia__show_less,onLess:function(){},onMore:function(){},errMsg:null,force:!1};return b&&a.extend(c,b),!(a(this).data("jquery.shorten")&&!c.force)&&(a(this).data("jquery.shorten",!0),a(document).off("click",".morelink"),a(document).on({click:function(){var b=a(this);return b.hasClass("less")?(b.removeClass("less"),b.html(c.moreText),b.parent().prev().hide(0,function(){b.parent().prev().prev().show()}).hide(0,function(){c.onLess()})):(b.addClass("less"),b.html(c.lessText),b.parent().prev().show(0,function(){b.parent().prev().prev().hide()}).show(0,function(){c.onMore()})),!1}},".morelink"),this.each(function(){var b=a(this),d=b.html();if(b.text().length>c.showChars+c.minHideChars){var e=d.substr(0,c.showChars);if(e.indexOf("<")>=0){for(var f=!1,g="",h=0,i=[],k=null,l=0,m=0;m<=c.showChars;l++)if("<"!=d[l]||f||(f=!0,k=d.substring(l+1,d.indexOf(">",l)),"/"==k[0]?k!="/"+i[0]?c.errMsg="ERROR en HTML: the top of the stack should be the tag that closes":i.shift():"br"!=k.toLowerCase()&&i.unshift(k)),f&&">"==d[l]&&(f=!1),f)g+=d.charAt(l);else if(m++,h<=c.showChars)g+=d.charAt(l),h++;else if(i.length>0){for(j=0;j<i.length;j++)g+="</"+i[j]+">";break}e=a("<div/>").html(g+'<span class="ellip">'+c.ellipsesText+"</span>").html()}else e+=c.ellipsesText;var n='<div class="shortcontent">'+e+'</div><div class="allcontent">'+d+'</div><span><a href="javascript://nop/" class="morelink">'+c.moreText+"</a></span>";b.html(n),b.find(".allcontent").hide(),a(".shortcontent p:last",b).css("margin-bottom",0)}}))}}(jQuery),window.onload=function(){"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container),rtm_search_media_text_validation(),check_condition("search")&&jQuery("#media_search_remove").show()},jQuery(document).ready(function(){rtm_upload_terms_activity()});
3
  * @package rtMedia
4
  */
5
 
6
+ function apply_rtMagnificPopup(a){jQuery("document").ready(function(b){var c="";if(c="undefined"==typeof rtmedia_load_more?"Loading media":rtmedia_load_more,"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled){var d,e,f=!1;b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").length>0&&b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").addClass("no-popup"),rtMagnificPopup=jQuery(a).magnificPopup({delegate:"a:not(.no-popup, .mejs-time-slider, .mejs-volume-slider, .mejs-horizontal-volume-slider)",type:"ajax",fixedContentPos:!0,fixedBgPos:!0,tLoading:c+" #%curr%...",mainClass:"mfp-img-mobile",preload:[1,3],closeOnBgClick:!0,gallery:{enabled:!0,navigateByImgClick:!0,arrowMarkup:"",preload:[0,1]},image:{tError:'<a href="%url%">The image #%curr%</a> could not be loaded.',titleSrc:function(a){return a.el.attr("title")+"<small>by Marsel Van Oosten</small>"}},callbacks:{ajaxContentAdded:function(){a=jQuery.magnificPopup.instance,1===jQuery(a.items).size()&&jQuery(".mfp-arrow").remove();var a=jQuery.magnificPopup.instance,c=a.currItem.el,g=c.parent();if(g.is("li")||(g=g.parent()),(g.is(":nth-last-child(2)")||g.is(":last-child"))&&g.find("a").hasClass("rtmedia-list-item-a")){g.next();"block"==jQuery("#rtMedia-galary-next").css("display")&&(f||(d=a.ev.children(),f=!0,e=nextpage),jQuery("#rtMedia-galary-next").click())}var h=a.items.length;if(a.index==h-1&&!g.is(":last-child"))return void c.click();var i={};"undefined"!=typeof _wpmejsSettings&&(i.pluginPath=_wpmejsSettings.pluginPath);var j=jQuery(".rtmedia-container .rtmedia-single-meta").height(),k=!1;void 0!==a&&void 0!==a.probablyMobile&&1==a.probablyMobile&&(k=!0),b(".mfp-content .rtmedia-single-media .wp-audio-shortcode,.mfp-content .rtmedia-single-media .wp-video-shortcode,.mfp-content .rtmedia-single-media .bp_media_content video").attr("autoplay",!0),k&&b(".mfp-content .rtmedia-single-media .wp-video-shortcode,.mfp-content .rtmedia-single-media .bp_media_content video").attr("muted",!1),b(".mfp-content .rtmedia-single-media .wp-audio-shortcode,.mfp-content .rtmedia-single-media .wp-video-shortcode,.mfp-content .rtmedia-single-media .bp_media_content video").mediaelementplayer({classPrefix:"mejs-",defaultVideoWidth:480,hideVolumeOnTouchDevices:!1,features:["playpause","progress","current","volume","fullscreen"],defaultVideoHeight:270,alwaysShowControls:k,enableAutosize:!0,clickToPlayPause:!0,videoHeight:-1,success:function(a,c){a.addEventListener("loadeddata",function(c){var d=b(a).height(),e=b(window).height(),f=jQuery("div.rtm-ltb-action-container").height(),f=f+50,g=j-f;d>e&&jQuery(".rtmedia-container #rtmedia-single-media-container .mejs-container").attr("style","height:"+g+"px !important; transition:0.2s")},!1),k&&b(a).hasClass("wp-video-shortcode")?jQuery("body").on("touchstart",".mejs-overlay-button",function(b){a.paused?a.play():a.pause()}):a.pause()}}),b(".mfp-content .mejs-audio .mejs-controls").css("position","relative"),rtMediaHook.call("rtmedia_js_popup_after_content_added",[]),"undefined"!=typeof bp&&void 0!==bp.mentions&&void 0!==bp.mentions.users&&(b("#atwho-container #atwho-ground-comment_content").remove(),b("#comment_content").bp_mentions(bp.mentions.users)),rtmedia_reset_video_and_audio_for_popup(),apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container")},open:function(){var a=jQuery(".mfp-bg"),b=jQuery(".mfp-wrap");a.height(a.height()+b.height())},close:function(a){f&&(mfp.ev.empty(),mfp.ev.append(d),nextpage=e,f=!1,nextpage>1&&jQuery("#rtMedia-galary-next").show()),rtmedia_single_page_popup_close()},BeforeChange:function(a){}}})}jQuery(document).ajaxComplete(function(){jQuery("[id^=imgedit-leaving]").filter(function(){var a=jQuery(this).text();jQuery(this).text(a.replace("OK","Save"))})})})}function rtmedia_init_action_dropdown(a){var b,c;jQuery(a+" .click-nav > span,"+a+" .click-nav > div").toggleClass("no-js js"),jQuery(a+" .click-nav .js ul").hide(),jQuery(a+" .click-nav .clicker").click(function(a){b=jQuery("#rtm-media-options .click-nav .clicker").next("ul"),c=jQuery(this).next("ul"),jQuery.each(b,function(a,b){jQuery(b).html()!=c.html()&&jQuery(b).hide()}),jQuery(c).toggle(),a.stopPropagation()})}function bp_media_create_element(a){return!1}function rtmedia_version_compare(a,b){if(typeof a+typeof b!="stringstring")return!1;for(var c=a.split("."),d=b.split("."),e=0,f=Math.max(c.length,d.length);e<f;e++){if(c[e]&&!d[e]&&parseInt(c[e])>0||parseInt(c[e])>parseInt(d[e]))return!0;if(d[e]&&!c[e]&&parseInt(d[e])>0||parseInt(c[e])<parseInt(d[e]))return!1}return!0}function rtm_is_element_exist(a){return jQuery(a).length>0}function rtm_masonry_reload(a){setTimeout(function(){a.masonry("reload")},250)}function rtm_search_media_text_validation(){""===jQuery("#media_search_input").val()?jQuery("#media_search").css("cursor","not-allowed"):jQuery("#media_search").css("cursor","pointer")}function rtmediaGetParameterByName(a){a=a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var b=new RegExp("[\\?&]"+a+"=([^&#]*)"),c=b.exec(location.search);return null==c?"":decodeURIComponent(c[1].replace(/\+/g," "))}function rtmedia_single_media_alert_message(a,b,c){var d="rtmedia-success";"warning"==b&&(d="rtmedia-warning");var e=!1;jQuery(".rtmedia-message-container").each(function(a,b){return b=jQuery(b),c&&b.hasClass("rtmedia-empty-comment-error-class")?(b.remove(),e=!0,!1):void 0!==c||b.hasClass("rtmedia-empty-comment-error-class")?void 0:(b.remove(),e=!0,!1)});var f=jQuery("<div>",{title:"Click to dismiss",class:"rtmedia-message-container"+(c?" rtmedia-empty-comment-error-class":""),style:"margin:1em 0;"}),g=jQuery("<span>",{class:d});g.html(a),g.appendTo(f);var h;c?(h=jQuery("#rt_media_comment_form"),jQuery("#comment_content").focus()):void 0===c&&(h=jQuery(".rtmedia-single-media .rtmedia-media"),h.css("opacity","0.2")),h.after(f),e&&(g.css({border:"2px solid #884646"}),setTimeout(function(){g.css({border:"none"})},500)),setTimeout(function(){f.remove(),void 0===c&&h.css("opacity","1")},3e3),f.click(function(){f.remove(),void 0===c&&h.css("opacity","1")})}function rtmedia_gallery_action_alert_message(a,b){var c="rtmedia-success";"warning"==b&&(c="rtmedia-warning");jQuery("body").append('<div class="rtmedia-gallery-alert-container"> </div>'),jQuery(".rtmedia-gallery-alert-container").append("<div class='rtmedia-gallery-message-box'><span class='"+c+"'>"+a+" </span></div>"),setTimeout(function(){jQuery(".rtmedia-gallery-alert-container").remove()},3e3),jQuery(".rtmedia-gallery-message-box").click(function(){jQuery(".rtmedia-gallery-alert-container").remove()})}function rtmedia_activity_masonry(){jQuery("#activity-stream .rtmedia-activity-container .rtmedia-list").masonry({itemSelector:".rtmedia-list-item",gutter:7});var a=0,b=setInterval(function(){a+=1,5===a&&clearInterval(b),jQuery.each(jQuery(".rtmedia-activity-container .rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())}),rtm_masonry_reload(jQuery("#activity-stream .rtmedia-activity-container .rtmedia-list"))},1e3)}function get_parameter(a,b){if(!a)return!1;b||(b=window.location.href);var a=a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]"),c=a+"=([^&#]*)",d=new RegExp(c),e=d.exec(b);return null!==e&&e[1]}function rtm_upload_terms_activity(){if(jQuery("#rtmedia_upload_terms_conditions").length>0){jQuery("#bp-nouveau-activity-form").on("click","#aw-whats-new-submit",function(a){var b=jQuery("#whats-new-form"),c=b.find("#rtmedia_upload_terms_conditions");if(0!==c.length&&!1===c.prop("checked")&&0===b.find("#message").length){a.preventDefault();var d=b.find(".rtmedia-upload-terms");rtp_display_terms_warning(d,rtmedia_upload_terms_check_terms_message)}});var a=jQuery("#whats-new-form");a.length>0&&jQuery("#whats-new-form, #rtmedia_upload_terms_conditions").on("click",function(b){a.find("input:hidden").each(function(){jQuery(this).prop("disabled",!1)})})}}!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h=function(){},i=!!window.jQuery,j=a(window),k=function(a,c){b.ev.on("mfp"+a+".mfp",c)},l=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},m=function(c,d){b.ev.triggerHandler("mfp"+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},n=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},o=function(){a.magnificPopup.instance||(b=new h,b.init(),a.magnificPopup.instance=b)},p=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};h.prototype={constructor:h,init:function(){var c=navigator.appVersion;b.isIE7=-1!==c.indexOf("MSIE 7."),b.isIE8=-1!==c.indexOf("MSIE 8."),b.isLowIE=b.isIE7||b.isIE8,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=p(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(!1===c.isObj){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",c.mainEl&&c.mainEl.length?b.ev=c.mainEl.eq(0):b.ev=d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=l("bg").on("click.mfp",function(){b.close()}),b.wrap=l("wrap").attr("tabindex",-1).on("click.mfp",function(a){b._checkIfClose(a.target)&&b.close()}),b.container=l("container",b.wrap)),b.contentContainer=l("content"),b.st.preloader&&(b.preloader=l("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var o=i[e];o=o.charAt(0).toUpperCase()+o.slice(1),b["init"+o].call(b)}m("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(k("MarkupParse",function(a,b,c,d){c.close_replaceWith=n(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(n())),b.st.alignTop&&(f+=" mfp-align-top"),b.fixedContentPos?b.wrap.css({overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.st.overflowY}):b.wrap.css({top:j.scrollTop(),position:"absolute"}),(!1===b.st.fixedBgPos||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup.mfp",function(a){27===a.keyCode&&b.close()}),j.on("resize.mfp",function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var p=b.wH=j.height(),q={};if(b.fixedContentPos&&b._hasScrollBar(p)){var r=b._getScrollbarSize();r&&(q.marginRight=r)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):q.overflow="hidden");var s=b.st.mainClass;return b.isIE7&&(s+=" mfp-ie7"),s&&b._addClassToMFP(s),b.updateItemHTML(),m("BuildControls"),a("html").css(q),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP("mfp-ready"),b._setFocus()):b.bgOverlay.addClass("mfp-ready"),d.on("focusin.mfp",b._onFocusIn)},16),b.isOpen=!0,b.updateSize(p),m("Open"),c},close:function(){b.isOpen&&(m("BeforeClose"),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP("mfp-removing"),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){m("Close");var c="mfp-removing mfp-ready ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup.mfp focusin.mfp"),b.ev.off(".mfp"),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&!0!==b.currTemplate[b.currItem.type]||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,m("AfterClose")},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||j.height();b.fixedContentPos||b.wrap.css("height",b.wH),m("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(m("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=!!b.st[d]&&b.st[d].markup;m("FirstMarkupParse",f),b.currTemplate[d]=!f||a(f)}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,m("Change",c),e=c.type,b.container.prepend(b.contentContainer),m("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&!0===b.currTemplate[c]?b.content.find(".mfp-close").length||b.content.append(n()):b.content=a:b.content="",m("BeforeAppend"),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,m("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){if((void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick)||2!==c.which&&!c.ctrlKey&&!c.metaKey){var f=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(f)if(a.isFunction(f)){if(!f.call(b))return!0}else if(j.width()<f)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};m("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass("mfp-prevent-close")){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||j.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){if(c.target!==b.wrap[0]&&!a.contains(b.wrap[0],c.target))return b._setFocus(),!1},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),m("MarkupParse",[b,c,d]),a.each(c,function(a,c){if(void 0===c||!1===c)return!0;if(e=a.split("_"),e.length>1){var d=b.find(".mfp-"+e[0]);if(d.length>0){var f=e[1];"replaceWith"===f?d[0]!==c[0]&&d.replaceWith(c):"img"===f?d.is("img")?d.attr("src",c):d.replaceWith('<img src="'+c+'" class="'+d.attr("class")+'" />'):d.attr(e[1],c)}}else b.find(".mfp-"+a).html(c)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:h.prototype,modules:[],open:function(b,c){return o(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&times;</button>',tClose:"Close (Esc)",tLoading:"Loading..."}},a.fn.magnificPopup=function(c){o();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=i?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),i?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var q,r,s,t=function(){s&&(r.after(s.addClass(q)).detach(),s=null)};a.magnificPopup.registerModule("inline",{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push("inline"),k("Close.inline",function(){t()})},getInline:function(c,d){if(t(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(r||(q=e.hiddenClass,r=l(q),q="mfp-"+q),s=f.after(r).detach().removeClass(q)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var u,v=function(){u&&a(document.body).removeClass(u)},w=function(){v(),b.req&&b.req.abort()};a.magnificPopup.registerModule("ajax",{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push("ajax"),u=b.st.ajax.cursor,k("Close.ajax",w),k("BeforeChange.ajax",w)},getAjax:function(c){u&&a(document.body).addClass(u),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};m("ParseAjax",g),b.appendContent(a(g.data),"ajax"),c.finished=!0,v(),b._setFocus(),setTimeout(function(){b.wrap.addClass("mfp-ready")},16),b.updateStatus("ready"),m("AjaxContentAdded")},error:function(){v(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var x,y=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),k("Open"+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),k("Close"+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),j.off("resize.mfp")}),k("Resize"+d,b.resizeImage),b.isLowIE&&k("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,x&&clearInterval(x),a.isCheckingImgSize=!1,m("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){x&&clearInterval(x),x=setInterval(function(){if(d.naturalWidth>0)return void b._onImageHasSize(a);c>200&&clearInterval(x),c++,3===c?e(10):40===c?e(50):100===c&&e(500)},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,m("ImageLoadComplete")):(e++,e<200?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:y(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(x&&clearInterval(x),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var z,A=function(){return void 0===z&&(z=void 0!==document.createElement("p").style.MozTransform),z};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,h=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},i=function(){b.content.css("visibility","visible")};k("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),!(a=b._getItemToZoom()))return void i();f=h(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){i(),setTimeout(function(){f.remove(),a=f=null,m("ZoomAnimationEnded")},16)},g)},16)}}),k("BeforeClose"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(!(a=b._getItemToZoom()))return;f=h(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),k("Close"+d,function(){b._allowZoom()&&(i(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return!!b.currItem.hasSize&&b.currItem.img},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(i?d.innerHeight():d[0].offsetHeight)-g-f};return A()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});var B=function(a){if(b.currTemplate.iframe){var c=b.currTemplate.iframe.find("iframe");c.length&&(a||(c[0].src="//about:blank"),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule("iframe",{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push("iframe"),k("BeforeChange",function(a,b,c){b!==c&&("iframe"===b?B():"iframe"===c&&B(!0))}),k("Close.iframe",function(){B()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){if(e.indexOf(this.index)>-1)return this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var C=function(a){var c=b.items.length;return a>c-1?a-c:a<0?c+a:a},D=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);if(b.direction=!0,!c||!c.enabled)return!1;f+=" mfp-gallery",k("Open"+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){if(b.items.length>1)return b.next(),!1}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),k("UpdateStatus"+e,function(a,c){c.text&&(c.text=D(c.text,b.currItem.index,b.items.length))}),k("MarkupParse"+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?D(c.tCounter,f.index,g):""}),k("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass("mfp-prevent-close"),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass("mfp-prevent-close"),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(l("b",e[0],!1,!0),l("a",e[0],!1,!0),l("b",f[0],!1,!0),l("a",f[0],!1,!0)),b.container.append(e.add(f))}}),k("Change"+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),k("Close"+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})},next:function(){b.direction=!0,b.index=C(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=C(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=C(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),m("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,m("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});a.magnificPopup.registerModule("retina",{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(k("ImageHasSize.retina",function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),k("ElementParse.retina",function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b="ontouchstart"in window,c=function(){j.off("touchmove"+d+" touchend"+d)},d=".mfpFastClick";a.fn.mfpFastClick=function(e){return a(this).each(function(){var f,g=a(this);if(b){var h,i,k,l,m,n;g.on("touchstart"+d,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],i=m.clientX,k=m.clientY,j.on("touchmove"+d,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-i)>10||Math.abs(m.clientY-k)>10)&&(l=!0,c())}).on("touchend"+d,function(a){c(),l||n>1||(f=!0,a.preventDefault(),clearTimeout(h),h=setTimeout(function(){f=!1},1e3),e())})})}g.on("click"+d,function(){f||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+d+" click"+d),b&&j.off("touchmove"+d+" touchend"+d)}}(),o()}),"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b}),function(a,b,c,d){var e={init:function(b,c){var d=this;d.elem=c,d.$elem=a(c),d.options=a.extend({},a.fn.rtTab.options,b),d.rtTabs()},rtTabs:function(){var c=this,d=c.options.activeTab;if(c.$elem.find("li:nth-child("+d+")").addClass("active"),c.rtTabContent(activeTabContent="yes"),c.rtClick(),!0==("false"!==c.$elem.attr("data-hash"))){var e=b.location.hash;e&&c.$elem.find("li").find('a[href="'+e+'"]').trigger("click"),a(b).on("hashchange",function(){var a=b.location.hash;c.$elem.find("li").find('a[href="'+a+'"]').trigger("click")})}},rtClick:function(){var c=this,d=c.$elem.find("li");d.find("a").on("click",function(e){e.preventDefault(),d.removeClass("active"),c.rtTabContent(),a(this).parent().addClass("active");var f=a(this).attr("href");if(a(f).removeClass("hide"),1==("false"!==c.$elem.attr("data-hash"))){var g=a(b).scrollTop();location.hash=a(this).attr("href"),a(b).scrollTop(g)}"function"==typeof c.options.onComplete&&c.options.onComplete.apply(c.elem,arguments)})},rtTabContent:function(b){this.$elem.find("li").find("a").each(function(){var c=a(this),d=c.attr("href");"yes"===b?c.parent().hasClass("active")||a(d).addClass("hide"):a(d).addClass("hide")})}};a.fn.rtTab=function(b){return this.each(function(){var c=Object.create(e);c.init(b,this),a.data(this,"rtTab",c)})},a.fn.rtTab.options={activeTab:1,onComplete:null}}(jQuery,window,document);var rtMagnificPopup,rtm_masonry_container,comment_media=!1,rtMediaHook={hooks:[],is_break:!1,register:function(a,b){void 0===rtMediaHook.hooks[a]&&(rtMediaHook.hooks[a]=[]),rtMediaHook.hooks[a].push(b)},call:function(a,arguments){if(void 0!==rtMediaHook.hooks[a])for(i=0;i<rtMediaHook.hooks[a].length;++i)if(1!=rtMediaHook.hooks[a][i](arguments))return rtMediaHook.is_break=!0,!1;return!0}};jQuery("document").ready(function(a){function b(){if(jQuery("#rtmedia-media-view-form").length>0){var a=jQuery("#rtmedia-media-view-form").attr("action");jQuery.post(a,{},function(a){})}}function c(){var a=jQuery.magnificPopup.instance,b=a.probablyMobile,c=e("rtmedia-touch-swipe-tooltip");b&&""===c?(jQuery("#mobile-swipe-overlay").show(),jQuery("#mobile-swipe-overlay").on("click",function(a){d("rtmedia-touch-swipe-tooltip",!0,365),jQuery(this).hide(),jQuery("#rtmedia-single-media-container .mejs-playpause-button").trigger("click")}),jQuery("#mobile-swipe-overlay").swipe({swipe:function(a,b,c,e,f,g){d("rtmedia-touch-swipe-tooltip",!0,365),jQuery("#mobile-swipe-overlay").hide(),
7
+ jQuery("#rtmedia-single-media-container .mejs-playpause-button").trigger("click")},threshold:0})):jQuery("#rtmedia-single-media-container .mejs-playpause-button").trigger("click"),jQuery(".mfp-arrow-right").on("click",function(b){a.next()}),jQuery(".mfp-arrow-left").on("click",function(b){a.prev()}),jQuery(".mfp-content .rtmedia-media").swipe({swipeLeft:function(b,c,d,e,f){a.next()},swipeRight:function(b,c,d,e,f){a.prev()},threshold:0})}function d(a,b,c){var d=new Date;d.setTime(d.getTime()+24*c*60*60*1e3);var e="expires="+d.toUTCString();document.cookie=a+"="+b+";"+e+";path=/"}function e(a){for(var b=a+"=",c=document.cookie.split(";"),d=0;d<c.length;d++){for(var e=c[d];" "==e.charAt(0);)e=e.substring(1);if(0==e.indexOf(b))return e.substring(b.length,e.length)}return""}function f(){jQuery(".mfp-arrow-right").hide(),jQuery(".mfp-arrow-left").hide(),jQuery(document).unbind("keydown")}function g(){rtmedia_disable_popup_navigation("#comment_content")}function h(){jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()})}jQuery(document).ajaxComplete(function(a,b,c){if("legacy"!==bp_template_pack&&bp_template_pack){var d=get_parameter("action",c.data);"activity_filter"!==d&&"post_update"!==d&&"get_single_activity_content"!==d&&"activity_get_older_updates"!==d||"undefined"==typeof rtmedia_masonry_layout||"true"!==rtmedia_masonry_layout||"undefined"==typeof rtmedia_masonry_layout_activity||"true"!==rtmedia_masonry_layout_activity?"activity_filter"!==d&&"post_update"!==d&&"get_single_activity_content"!==d&&"activity_get_older_updates"!==d||setTimeout(function(){apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),rtmedia_activity_stream_comment_media()},1e3):setTimeout(function(){apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),rtmedia_activity_masonry(),rtmedia_activity_stream_comment_media()},1e3)}}),jQuery(".rtmedia-uploader-div").css({opacity:"1",display:"block",visibility:"visible"}),jQuery(" #whats-new-options ").css({opacity:"1"}),void 0!==a.fn.rtTab&&a(".rtm-tabs").rtTab(),jQuery(".rtmedia-modal-link").length>0&&a(".rtmedia-modal-link").magnificPopup({type:"inline",midClick:!0,closeBtnInside:!0}),a("#rt_media_comment_form").submit(function(b){return""!=a.trim(a("#comment_content").val())||(0==jQuery("#rtmedia-single-media-container").length?rtmedia_gallery_action_alert_message(rtmedia_empty_comment_msg,"warning"):rtmedia_single_media_alert_message(rtmedia_empty_comment_msg,"warning"),!1)}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&apply_rtMagnificPopup(".rtmedia-list-media.rtm-gallery-list, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||void 0===b.data||void 0===b.data.action)return!0}catch(a){return!0}if("activity_get_older_updates"==b.data.action){var d=b.success;a.success=function(a){"function"==typeof d&&d(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}else if("get_single_activity_content"==b.data.action){var d=b.success;a.success=function(a){"function"==typeof d&&d(a),setTimeout(function(){apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),jQuery("ul.activity-list li.rtmedia_update:first-child .wp-audio-shortcode, ul.activity-list li.rtmedia_update:first-child .wp-video-shortcode").mediaelementplayer({classPrefix:"mejs-",defaultVideoWidth:480,defaultVideoHeight:270})},900)}}}),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||void 0===b.data||void 0===b.data.action)return!0}catch(a){return!0}if("activity_get_older_updates"==b.data.action){var d=b.success;a.success=function(a){"function"==typeof d&&d(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),jQuery("ul.activity-list li.rtmedia_update div.rtmedia-item-thumbnail > audio.wp-audio-shortcode, ul.activity-list li.rtmedia_update div.rtmedia-item-thumbnail > video.wp-video-shortcode").mediaelementplayer({classPrefix:"mejs-",defaultVideoWidth:480,defaultVideoHeight:270}),setTimeout(function(){rtmedia_activity_stream_comment_media()},900),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}}),jQuery(".rtmedia-container").on("click",".select-all",function(a){jQuery(this).toggleClass("unselect-all").toggleClass("select-all"),jQuery(this).attr("title",rtmedia_unselect_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!0)}),jQuery(".rtmedia-list-item").addClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".unselect-all",function(a){jQuery(this).toggleClass("select-all").toggleClass("unselect-all"),jQuery(this).attr("title",rtmedia_select_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!1)}),jQuery(".rtmedia-list-item").removeClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".rtmedia-move",function(a){jQuery(".rtmedia-delete-container").slideUp(),jQuery(".rtmedia-move-container").slideToggle()}),jQuery("#rtmedia-create-album-modal").on("click","#rtmedia_create_new_album",function(b){if($albumname=jQuery("<span/>").text(jQuery.trim(jQuery("#rtmedia_album_name").val())).html(),$album_description=jQuery("#rtmedia_album_description"),$context=jQuery.trim(jQuery("#rtmedia_album_context").val()),$context_id=jQuery.trim(jQuery("#rtmedia_album_context_id").val()),$privacy=jQuery.trim(jQuery("#rtmedia_select_album_privacy").val()),$create_album_nonce=jQuery.trim(jQuery("#rtmedia_create_album_nonce").val()),""!=$albumname){var c={action:"rtmedia_create_album",name:$albumname,description:$album_description.val(),context:$context,context_id:$context_id,create_album_nonce:$create_album_nonce};""!==$privacy&&(c.privacy=$privacy),a("#rtmedia_create_new_album").attr("disabled","disabled");var d=a("#rtmedia_create_new_album").html();a("#rtmedia_create_new_album").prepend("<img src='"+rMedia_loading_file+"' />"),jQuery.post(rtmedia_ajax_url,c,function(b){if(void 0!==b.album){b=jQuery.trim(b.album);var c=!0;$album_description.val(""),a("#rtmedia_album_name").focus(),jQuery(".rtmedia-user-album-list").each(function(){if(jQuery(this).children("optgroup").each(function(){if(jQuery(this).attr("value")===$context)return c=!1,void jQuery(this).append('<option value="'+b+'">'+$albumname+"</option>")}),c){var a=$context.charAt(0).toUpperCase()+$context.slice(1)+" "+rtmedia_main_js_strings.rtmedia_albums,d='<optgroup value="'+$context+'" label="'+a+'"><option value="'+b+'">'+$albumname+"</option></optgroup>";jQuery(this).append(d)}}),jQuery('select.rtmedia-user-album-list option[value="'+b+'"]').prop("selected",!0),jQuery(".rtmedia-create-new-album-container").slideToggle(),jQuery("#rtmedia_album_name").val(""),jQuery("#rtmedia-create-album-modal").append("<div class='rtmedia-success rtmedia-create-album-alert'><b>"+$albumname+"</b>"+rtmedia_album_created_msg+"</div>"),setTimeout(function(){jQuery(".rtmedia-create-album-alert").remove()},4e3),setTimeout(function(){galleryObj.reloadView(),jQuery(".close-reveal-modal").click()},2e3)}else void 0!==b.error?rtmedia_gallery_action_alert_message(b.error,"warning"):rtmedia_gallery_action_alert_message(rtmedia_something_wrong_msg,"warning");a("#rtmedia_create_new_album").removeAttr("disabled"),a("#rtmedia_create_new_album").html(d)})}else rtmedia_gallery_action_alert_message(rtmedia_empty_album_name_msg,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_delete_confirmation)&&jQuery(this).closest("form").attr("action","../../../"+rtmedia_media_slug+"/delete").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-move-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_move_confirmation)&&jQuery(this).closest("form").attr("action","").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery("#buddypress").on("change",".rtm-activity-privacy-opt",function(){var a=jQuery(this).attr("id");a=a.split("-"),a=a[a.length-1];var b=this;data={activity_id:a,privacy:jQuery(this).val(),nonce:jQuery("#rtmedia_activity_privacy_nonce").val(),action:"rtm_change_activity_privacy"},jQuery.post(ajaxurl,data,function(a){var c="",d="";"true"==a?(c=rtmedia_main_js_strings.privacy_update_success,d="success"):(c=rtmedia_main_js_strings.privacy_update_error,d="fail"),jQuery(b).after('<p class="rtm-ac-privacy-updated '+d+'">'+c+"</p>"),setTimeout(function(){jQuery(b).siblings(".rtm-ac-privacy-updated").remove()},2e3)})}),jQuery(".media_search_input").on("keyup",function(){rtm_search_media_text_validation()}),b(),rtMediaHook.register("rtmedia_js_popup_after_content_added",function(){b(),h(),mfp=jQuery.magnificPopup.instance,jQuery(mfp.items).size()>1&&0==comment_media?c():f(),g(),rtmedia_disable_popup_navigation_comment_media_focus();var d=a(window).height();jQuery(".rtm-lightbox-container .mejs-video").css({height:.8*d,"over-flow":"hidden"}),jQuery(".mfp-content .rtmedia-media").css({"max-height":.87*d,"over-flow":"hidden"}),rtmedia_init_action_dropdown(".rtm-lightbox-container .rtmedia-actions"),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").shorten({showChars:130});var e=a(".rtm-gallery-title"),i="";""!=(i=a.isEmptyObject(e)?a("#subnav.item-list-tabs li.selected ").html():e.html())&&a(".rtm-ltb-gallery-title .ltb-title").html(i);var j=a("#subnav.item-list-tabs li.selected span").html();return a("li.total").html(j),!0});var i=jQuery("#drag-drop-area"),j=jQuery("#whats-new");i.html();jQuery("#rtmedia-upload-container").after("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&jQuery("#whats-new-textarea").append("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),jQuery(document).on("dragover",function(a){a.preventDefault(),a.target!=this&&(jQuery("#rtm-media-gallery-uploader").show(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&j.addClass("rtm-drag-drop-active"),i.addClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").show())}).on("dragleave",function(a){if(a.preventDefault(),0!=a.originalEvent.pageX&&0!=a.originalEvent.pageY)return!1;"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(j.removeClass("rtm-drag-drop-active"),j.removeAttr("style")),i.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}).on("drop",function(a){a.preventDefault(),jQuery(".bp-suggestions").focus(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(j.removeClass("rtm-drag-drop-active"),j.removeAttr("style")),i.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-album",function(a){a.preventDefault(),confirm(rtmedia_album_delete_confirmation)&&jQuery(this).closest("form").submit()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()}),rtmedia_init_action_dropdown(""),a(document).click(function(){a(".click-nav ul").is(":visible")&&a(".click-nav ul",this).hide()}),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").length>0&&a(".rtm-more").shorten({showChars:200}),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&"undefined"!=typeof rtmedia_masonry_layout_activity&&"true"==rtmedia_masonry_layout_activity&&rtmedia_activity_masonry(),jQuery(document).ajaxComplete(function(a,b,c){var d=get_parameter("action",c.data);"post_update"!==d&&"get_single_activity_content"!==d&&"activity_get_older_updates"!==d||"undefined"==typeof rtmedia_masonry_layout||"true"!=rtmedia_masonry_layout||"undefined"==typeof rtmedia_masonry_layout_activity||"true"!=rtmedia_masonry_layout_activity||rtmedia_activity_masonry()}),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&(rtm_masonry_container=jQuery(".rtmedia-container .rtmedia-list"),rtm_masonry_container.masonry({itemSelector:".rtmedia-list-item"}),setInterval(function(){jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())}),rtm_masonry_reload(rtm_masonry_container)},1e3),jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())})),jQuery(".rtm-uploader-tabs").length>0&&jQuery(".rtm-uploader-tabs li").click(function(a){jQuery(this).hasClass("active")||(jQuery(this).siblings().removeClass("active"),jQuery(this).parents(".rtm-uploader-tabs").siblings().hide(),class_name=jQuery(this).attr("class"),jQuery(this).parents(".rtm-uploader-tabs").siblings('[data-id="'+class_name+'"]').show(),jQuery(this).addClass("active"),"rtm-upload-tab"!=class_name?jQuery("div.moxie-shim").hide():jQuery("div.moxie-shim").show())}),jQuery(".rtmedia-container").on("click",".rtm-delete-media",function(a){a.preventDefault();var b="Are you sure you want to delete this media?";if("undefined"!=typeof rtmedia_media_delete_confirmation&&(b=rtmedia_media_delete_confirmation),confirm(b)){var c=jQuery(this).closest("li"),d=jQuery("#rtmedia_media_delete_nonce").val(),e={action:"delete_uploaded_media",nonce:d,media_id:c.attr("id")};jQuery.ajax({url:ajaxurl,type:"post",data:e,success:function(a){"1"==a?(rtmedia_gallery_action_alert_message(rtmedia_main_js_strings.file_delete_success,"success"),c.remove(),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container)):rtmedia_gallery_action_alert_message(rtmedia_file_not_deleted,"warning")}})}})}),function(a){a.fn.shorten=function(b){"use strict";var c={showChars:100,minHideChars:10,ellipsesText:"...",moreText:rtmedia_read_more,lessText:rtmedia__show_less,onLess:function(){},onMore:function(){},errMsg:null,force:!1};return b&&a.extend(c,b),!(a(this).data("jquery.shorten")&&!c.force)&&(a(this).data("jquery.shorten",!0),a(document).off("click",".morelink"),a(document).on({click:function(){var b=a(this);return b.hasClass("less")?(b.removeClass("less"),b.html(c.moreText),b.parent().prev().hide(0,function(){b.parent().prev().prev().show()}).hide(0,function(){c.onLess()})):(b.addClass("less"),b.html(c.lessText),b.parent().prev().show(0,function(){b.parent().prev().prev().hide()}).show(0,function(){c.onMore()})),!1}},".morelink"),this.each(function(){var b=a(this),d=b.html();if(b.text().length>c.showChars+c.minHideChars){var e=d.substr(0,c.showChars);if(e.indexOf("<")>=0){for(var f=!1,g="",h=0,i=[],k=null,l=0,m=0;m<=c.showChars;l++)if("<"!=d[l]||f||(f=!0,k=d.substring(l+1,d.indexOf(">",l)),"/"==k[0]?k!="/"+i[0]?c.errMsg="ERROR en HTML: the top of the stack should be the tag that closes":i.shift():"br"!=k.toLowerCase()&&i.unshift(k)),f&&">"==d[l]&&(f=!1),f)g+=d.charAt(l);else if(m++,h<=c.showChars)g+=d.charAt(l),h++;else if(i.length>0){for(j=0;j<i.length;j++)g+="</"+i[j]+">";break}e=a("<div/>").html(g+'<span class="ellip">'+c.ellipsesText+"</span>").html()}else e+=c.ellipsesText;var n='<div class="shortcontent">'+e+'</div><div class="allcontent">'+d+'</div><span><a href="javascript://nop/" class="morelink">'+c.moreText+"</a></span>";b.html(n),b.find(".allcontent").hide(),a(".shortcontent p:last",b).css("margin-bottom",0)}}))}}(jQuery),window.onload=function(){"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container),rtm_search_media_text_validation(),check_condition("search")&&jQuery("#media_search_remove").show()},jQuery(document).ready(function(){rtm_upload_terms_activity(),jQuery("body").hasClass("has-sidebar")&&0===jQuery("#secondary").length&&(jQuery(".rtmedia-single-container").length||jQuery(".rtmedia-container").length)&&jQuery("body").removeClass("has-sidebar")});
app/helper/RTMediaSupport.php CHANGED
@@ -487,7 +487,7 @@ if ( ! class_exists( 'RTMediaSupport' ) ) {
487
  for="name"><?php esc_html_e( 'Name', 'buddypress-media' ); ?></label>
488
  <input class="bp-media-input" id="name" type="text" name="name" value="" required/>
489
  <span class="rtm-tooltip">
490
- <i class="dashicons dashicons-info rtmicon"></i>
491
  <span class="rtm-tip">
492
  <?php esc_html_e( 'Use actual user name which used during purchased.', 'buddypress-media' ); ?>
493
  </span>
@@ -499,7 +499,7 @@ if ( ! class_exists( 'RTMediaSupport' ) ) {
499
  for="email"><?php esc_html_e( 'Email', 'buddypress-media' ); ?></label>
500
  <input id="email" class="bp-media-input" type="text" name="email" value="" required/>
501
  <span class="rtm-tooltip">
502
- <i class="dashicons dashicons-info rtmicon"></i>
503
  <span class="rtm-tip">
504
  <?php esc_html_e( 'Use email id which used during purchased', 'buddypress-media' ); ?>
505
  </span>
@@ -543,7 +543,7 @@ if ( ! class_exists( 'RTMediaSupport' ) ) {
543
  for="subject"><?php esc_html_e( 'Attachement', 'buddypress-media' ); ?></label>
544
  <input id="debuglog" class="bp-media-input" type="file" name="debuglog" />
545
  <span class="rtm-tooltip">
546
- <i class="dashicons dashicons-info rtmicon"></i>
547
  <span class="rtm-tip">
548
  <?php esc_html_e( 'Allowed file types are : images, documents and texts.', 'buddypress-media' ); ?>
549
  </span>
487
  for="name"><?php esc_html_e( 'Name', 'buddypress-media' ); ?></label>
488
  <input class="bp-media-input" id="name" type="text" name="name" value="" required/>
489
  <span class="rtm-tooltip">
490
+ <i class="dashicons dashicons-info"></i>
491
  <span class="rtm-tip">
492
  <?php esc_html_e( 'Use actual user name which used during purchased.', 'buddypress-media' ); ?>
493
  </span>
499
  for="email"><?php esc_html_e( 'Email', 'buddypress-media' ); ?></label>
500
  <input id="email" class="bp-media-input" type="text" name="email" value="" required/>
501
  <span class="rtm-tooltip">
502
+ <i class="dashicons dashicons-info"></i>
503
  <span class="rtm-tip">
504
  <?php esc_html_e( 'Use email id which used during purchased', 'buddypress-media' ); ?>
505
  </span>
543
  for="subject"><?php esc_html_e( 'Attachement', 'buddypress-media' ); ?></label>
544
  <input id="debuglog" class="bp-media-input" type="file" name="debuglog" />
545
  <span class="rtm-tooltip">
546
+ <i class="dashicons dashicons-info"></i>
547
  <span class="rtm-tip">
548
  <?php esc_html_e( 'Allowed file types are : images, documents and texts.', 'buddypress-media' ); ?>
549
  </span>
app/main/controllers/activity/RTMediaActivity.php CHANGED
@@ -34,16 +34,31 @@ class RTMediaActivity {
34
  $this->privacy = $privacy;
35
  }
36
 
37
- function create_activity_html( $type = 'activity' ) {
38
-
39
- $html = '';
40
-
41
- $html .= '<div class="rtmedia-'.$type.'-container">';
42
-
43
- if ( ! empty( $this->activity_text ) ) {
44
- $html .= '<div class="rtmedia-'.$type.'-text"><span>';
45
- $html .= $this->activity_text;
46
- $html .= '</span></div>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  }
48
 
49
  global $rtmedia;
@@ -53,57 +68,122 @@ class RTMediaActivity {
53
  $limit_activity_feed = 0;
54
  }
55
 
56
- $mediaObj = new RTMediaModel();
57
- $media_details = $mediaObj->get( array( 'id' => $this->media ) );
58
 
59
  if ( intval( $limit_activity_feed ) > 0 ) {
60
  $media_details = array_slice( $media_details, 0, $limit_activity_feed, true );
61
  }
62
- $rtmedia_activity_ul_class = apply_filters( 'rtmedia_'.$type.'_ul_class', 'rtm-activity-media-list' );
63
- $li_content = '';
64
- $count = 0;
65
- foreach ( $media_details as $media ) {
66
- $li_content .= '<li class="rtmedia-list-item media-type-' . esc_attr( $media->media_type ) . '">';
67
- if ( 'photo' === $media->media_type || 'document' === $media->media_type || 'other' === $media->media_type ) {
68
- $li_content .= '<a href ="' . esc_url( get_rtmedia_permalink( $media->id ) ) . '">';
69
- }
70
- $li_content .= '<div class="rtmedia-item-thumbnail">';
71
-
72
- $li_content .= $this->media( $media );
73
 
74
- $li_content .= '</div>';
75
-
76
- $li_content .= '<div class="rtmedia-item-title">';
77
- $li_content .= '<h4 title="' . esc_attr( $media->media_title ) . '">';
78
- if ( 'photo' !== $media->media_type && 'document' !== $media->media_type && 'other' !== $media->media_type ) {
79
- $li_content .= '<a href="' . esc_url( get_rtmedia_permalink( $media->id ) ) . '">';
80
- }
81
 
82
- $li_content .= $media->media_title;
83
- if ( 'photo' !== $media->media_type && 'document' !== $media->media_type && 'other' !== $media->media_type ) {
84
- $li_content .= '</a>';
85
- }
86
- $li_content .= '</h4>';
87
- $li_content .= '</div>';
88
- if ( 'photo' === $media->media_type || 'document' === $media->media_type || 'other' === $media->media_type ) {
89
- $li_content .= '</a>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
 
92
- $li_content .= '</li>';
93
  $count ++;
94
  }
95
 
96
- if( 'activity' == $type ){
97
- $html .= '<ul class="rtmedia-list ' . esc_attr( $rtmedia_activity_ul_class ) . ' rtmedia-activity-media-length-' . esc_attr( $count ) . '">';
98
- }else{
99
- $html .= '<ul class="rtmedia-'.$type.'-list ' . esc_attr( $rtmedia_activity_ul_class ) . ' rtmedia-activity-media-length-' . esc_attr( $count ) . '">';
100
  }
101
 
102
- $html .= $li_content;
103
- $html .= '</ul>';
104
- $html .= '</div>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
- return bp_activity_filter_kses( $html );
107
  }
108
 
109
  /**
34
  $this->privacy = $privacy;
35
  }
36
 
37
+ /**
38
+ * Function is used to generate HTML of activity/comments.
39
+ * It combines the rtMedia text and media in the activity content.
40
+ *
41
+ * Note: Use the `rtmedia_activity_content_html` filter to modify the output of the activity content.
42
+ *
43
+ * @param string $type Type of activity (activity/comment).
44
+ *
45
+ * @return string
46
+ */
47
+ public function create_activity_html( $type = 'activity' ) {
48
+ $activity_container_start = sprintf( '<div class="rtmedia-%s-container">', esc_attr( $type ) );
49
+ $activity_container_end = '</div>';
50
+
51
+ $activity_text = '';
52
+
53
+ // Activity text content markup.
54
+ if ( ! empty( $this->activity_text ) && '&nbsp;' !== $this->activity_text ) {
55
+ $activity_text .= sprintf(
56
+ '<div class="rtmedia-%s-text">
57
+ <span>%s</span>
58
+ </div>',
59
+ esc_attr( $type ),
60
+ $this->activity_text
61
+ );
62
  }
63
 
64
  global $rtmedia;
68
  $limit_activity_feed = 0;
69
  }
70
 
71
+ $rtmedia_model = new RTMediaModel();
72
+ $media_details = $rtmedia_model->get( array( 'id' => $this->media ) );
73
 
74
  if ( intval( $limit_activity_feed ) > 0 ) {
75
  $media_details = array_slice( $media_details, 0, $limit_activity_feed, true );
76
  }
77
+ $rtmedia_activity_ul_class = apply_filters( 'rtmedia_' . $type . '_ul_class', 'rtm-activity-media-list' );
 
 
 
 
 
 
 
 
 
 
78
 
79
+ $media_content = '';
80
+ $count = 0;
81
+ foreach ( $media_details as $media ) {
82
+ $media_content .= sprintf( '<li class="rtmedia-list-item media-type-%s">', esc_attr( $media->media_type ) );
 
 
 
83
 
84
+ if ( 'photo' === $media->media_type ) {
85
+ // Markup for photo media type with anchor tag only on image.
86
+ $media_content .= sprintf(
87
+ '<a href ="%s">
88
+ <div class="rtmedia-item-thumbnail">
89
+ %s
90
+ </div>
91
+ <div class="rtmedia-item-title">
92
+ <h4 title="%s">
93
+ %s
94
+ </h4>
95
+ </div>
96
+ </a>',
97
+ esc_url( get_rtmedia_permalink( $media->id ) ),
98
+ $this->media( $media ),
99
+ esc_attr( $media->media_title ),
100
+ $media->media_title
101
+ );
102
+ } elseif ( 'music' === $media->media_type || 'video' === $media->media_type ) {
103
+ // Markup for audio and video media type with link only on media (title).
104
+ $media_content .= sprintf(
105
+ '<div class="rtmedia-item-thumbnail">
106
+ %s
107
+ </div>
108
+ <div class="rtmedia-item-title">
109
+ <h4 title="%s">
110
+ <a href="%s">
111
+ %s
112
+ </a>
113
+ </h4>
114
+ </div>',
115
+ $this->media( $media ),
116
+ esc_attr( $media->media_title ),
117
+ esc_url( get_rtmedia_permalink( $media->id ) ),
118
+ esc_html( $media->media_title )
119
+ );
120
+ } else {
121
+ // Markup for all the other media linke docs and other files where anchor tag the markup is comming from add-on itself.
122
+ $media_content .= sprintf(
123
+ '<div class="rtmedia-item-thumbnail">
124
+ %s
125
+ </div>
126
+ <div class="rtmedia-item-title">
127
+ <h4 title="%s">
128
+ %s
129
+ </h4>
130
+ </div>',
131
+ $this->media( $media ),
132
+ esc_attr( $media->media_title ),
133
+ esc_html( $media->media_title )
134
+ );
135
  }
136
 
137
+ $media_content .= '</li>';
138
  $count ++;
139
  }
140
 
141
+ $media_container_start_class = 'rtmedia-list';
142
+ if ( 'activity' !== $type ) {
143
+ $media_container_start_class = sprintf( 'rtmedia-%s-list', $type );
 
144
  }
145
 
146
+ $media_container_start = sprintf(
147
+ '<ul class="%s %s rtmedia-activity-media-length-%s">',
148
+ esc_attr( $media_container_start_class ),
149
+ esc_attr( $rtmedia_activity_ul_class ),
150
+ esc_attr( $count )
151
+ );
152
+
153
+ $media_container_end = '</ul>';
154
+
155
+ $media_list = $media_container_start;
156
+ $media_list .= $media_content;
157
+ $media_list .= $media_container_end;
158
+
159
+ /**
160
+ * Filters the output of the activity contents before save.
161
+ *
162
+ * @param string $activity_content Concatination of $activity_text and $media_list.
163
+ * @param string $activity_text HTML markup of activity text.
164
+ * @param string $media_list HTML markup of media in ul.
165
+ */
166
+ $activity_content = apply_filters( 'rtmedia_activity_content_html', $activity_text . $media_list, $activity_text, $media_list );
167
+
168
+ $activity = $activity_container_start;
169
+ $activity .= $activity_content;
170
+ $activity .= $activity_container_end;
171
+
172
+ // Bypass comment links limit.
173
+ add_filter(
174
+ 'option_comment_max_links',
175
+ function ( $values ) {
176
+ $rtmedia_attached_files = filter_input( INPUT_POST, 'rtMedia_attached_files', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
177
+ // Check if files available.
178
+ if ( is_array( $rtmedia_attached_files ) && ! empty( $rtmedia_attached_files[0] ) ) {
179
+ // One url of image and other for anchor tag.
180
+ $values = count( $rtmedia_attached_files ) * 3;
181
+ }
182
+ return $values;
183
+ }
184
+ );
185
 
186
+ return bp_activity_filter_kses( $activity );
187
  }
188
 
189
  /**
app/main/controllers/activity/RTMediaBuddyPressActivity.php CHANGED
@@ -339,6 +339,7 @@ class RTMediaBuddyPressActivity {
339
 
340
  $rtmedia_attached_files = filter_input( INPUT_POST, 'rtMedia_attached_files', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
341
  if ( is_array( $rtmedia_attached_files ) ) {
 
342
  $media_obj = new RTMediaModel();
343
  //Credit faisal : https://gist.github.com/faishal/c4306ae7267fff976465
344
  $in_str_arr = array_fill( 0, count( $rtmedia_attached_files ), '%d' );
@@ -437,6 +438,15 @@ class RTMediaBuddyPressActivity {
437
  }
438
 
439
  function bp_after_activity_post_form() {
 
 
 
 
 
 
 
 
 
440
  $request_uri = rtm_get_server_var( 'REQUEST_URI', 'FILTER_SANITIZE_URL' );
441
  $url = rtmedia_get_upload_url( $request_uri );
442
  if ( rtmedia_is_uploader_view_allowed( true, 'activity' ) ) {
@@ -856,6 +866,7 @@ class RTMediaBuddyPressActivity {
856
  }
857
 
858
  // create BuddyPress activity
 
859
  $activity_id = bp_activity_add( $activity_args );
860
 
861
  /* save the profile activity id in the media meta */
339
 
340
  $rtmedia_attached_files = filter_input( INPUT_POST, 'rtMedia_attached_files', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
341
  if ( is_array( $rtmedia_attached_files ) ) {
342
+ bp_activity_update_meta( $activity_id, 'bp_activity_text', bp_activity_filter_kses( $content ) );
343
  $media_obj = new RTMediaModel();
344
  //Credit faisal : https://gist.github.com/faishal/c4306ae7267fff976465
345
  $in_str_arr = array_fill( 0, count( $rtmedia_attached_files ), '%d' );
438
  }
439
 
440
  function bp_after_activity_post_form() {
441
+
442
+ /**
443
+ * Filter to enable/disable media upload from the activity.
444
+ *
445
+ * @param bool Default true to enable activity media upload false to disable activity media upload.
446
+ */
447
+ if ( ! apply_filters( 'rtmedia_enable_activity_media_upload', true ) ) {
448
+ return;
449
+ }
450
  $request_uri = rtm_get_server_var( 'REQUEST_URI', 'FILTER_SANITIZE_URL' );
451
  $url = rtmedia_get_upload_url( $request_uri );
452
  if ( rtmedia_is_uploader_view_allowed( true, 'activity' ) ) {
866
  }
867
 
868
  // create BuddyPress activity
869
+ remove_filter( 'bp_activity_content_before_save', array( $this, 'bp_activity_content_before_save' ) );
870
  $activity_id = bp_activity_add( $activity_args );
871
 
872
  /* save the profile activity id in the media meta */
app/main/controllers/media/RTMediaAlbum.php CHANGED
@@ -26,7 +26,7 @@ class RTMediaAlbum {
26
  */
27
  public function __construct() {
28
  add_action( 'init', array( &$this, 'register_post_types' ), 12 );
29
- add_action( 'init', array( &$this, 'rtmedia_album_custom_post_status', 13 ) );
30
  $this->media = new RTMediaMedia();
31
  }
32
 
26
  */
27
  public function __construct() {
28
  add_action( 'init', array( &$this, 'register_post_types' ), 12 );
29
+ add_action( 'init', array( &$this, 'rtmedia_album_custom_post_status' ), 13 );
30
  $this->media = new RTMediaMedia();
31
  }
32
 
app/main/controllers/media/RTMediaFeatured.php CHANGED
@@ -30,7 +30,7 @@ class RTMediaFeatured extends RTMediaUserInteraction {
30
  'single' => true,
31
  'repeatable' => false,
32
  'undoable' => true,
33
- 'icon_class' => 'dashicons dashicons-star-filled rtmicon',
34
  );
35
 
36
  $this->user_id = $user_id;
30
  'single' => true,
31
  'repeatable' => false,
32
  'undoable' => true,
33
+ 'icon_class' => 'dashicons dashicons-star-filled',
34
  );
35
 
36
  $this->user_id = $user_id;
app/main/controllers/media/RTMediaGalleryItemAction.php CHANGED
@@ -60,11 +60,11 @@ class RTMediaGalleryItemAction {
60
  <div class='rtmedia-gallery-item-actions'>
61
  <a href="<?php rtmedia_permalink(); ?>edit" class='no-popup' target='_blank'
62
  title='<?php esc_attr_e( 'Edit this media', 'buddypress-media' ); ?>'>
63
- <i class='dashicons dashicons-edit rtmicon'></i><?php esc_html_e( 'Edit', 'buddypress-media' ); ?>
64
  </a>
65
  <a href="#" class="no-popup rtm-delete-media"
66
  title='<?php esc_attr_e( 'Delete this media', 'buddypress-media' ); ?>'>
67
- <i class='dashicons dashicons-trash rtmicon'></i><?php esc_html_e( 'Delete', 'buddypress-media' ); ?>
68
  </a>
69
  </div>
70
  <?php
@@ -77,7 +77,7 @@ class RTMediaGalleryItemAction {
77
  $context_id = $media_array->context_id;
78
  $user_id = get_current_user_id();
79
 
80
- $media_array->media_actions = "<div class='rtmedia-gallery-item-actions'><a href='" . esc_url( $media_array->rt_permalink ) . "edit' class='no-popup' target='_blank' title='" . esc_attr__( 'Edit this media', 'buddypress-media' ) . "'><i class='dashicons dashicons-edit rtmicon'></i>" . esc_html__( 'Edit', 'buddypress-media' ) . "</a><a href='#' class='no-popup rtm-delete-media' title='" . esc_attr__( 'Delete this media', 'buddypress-media' ) . "' ><i class='dashicons dashicons-trash rtmicon'></i>" . esc_html__( 'Delete', 'buddypress-media' ) . '</a></div>';
81
  if ( ! ( is_rt_admin() || ( function_exists( 'groups_is_user_mod' ) && groups_is_user_mod( $user_id, $context_id ) ) || intval( $media_array->media_author ) === get_current_user_id() ) ) {
82
  $media_array->media_actions = '';
83
  }
60
  <div class='rtmedia-gallery-item-actions'>
61
  <a href="<?php rtmedia_permalink(); ?>edit" class='no-popup' target='_blank'
62
  title='<?php esc_attr_e( 'Edit this media', 'buddypress-media' ); ?>'>
63
+ <i class='dashicons dashicons-edit'></i><?php esc_html_e( 'Edit', 'buddypress-media' ); ?>
64
  </a>
65
  <a href="#" class="no-popup rtm-delete-media"
66
  title='<?php esc_attr_e( 'Delete this media', 'buddypress-media' ); ?>'>
67
+ <i class='dashicons dashicons-trash'></i><?php esc_html_e( 'Delete', 'buddypress-media' ); ?>
68
  </a>
69
  </div>
70
  <?php
77
  $context_id = $media_array->context_id;
78
  $user_id = get_current_user_id();
79
 
80
+ $media_array->media_actions = "<div class='rtmedia-gallery-item-actions'><a href='" . esc_url( $media_array->rt_permalink ) . "edit' class='no-popup' target='_blank' title='" . esc_attr__( 'Edit this media', 'buddypress-media' ) . "'><i class='dashicons dashicons-edit'></i>" . esc_html__( 'Edit', 'buddypress-media' ) . "</a><a href='#' class='no-popup rtm-delete-media' title='" . esc_attr__( 'Delete this media', 'buddypress-media' ) . "' ><i class='dashicons dashicons-trash'></i>" . esc_html__( 'Delete', 'buddypress-media' ) . '</a></div>';
81
  if ( ! ( is_rt_admin() || ( function_exists( 'groups_is_user_mod' ) && groups_is_user_mod( $user_id, $context_id ) ) || intval( $media_array->media_author ) === get_current_user_id() ) ) {
82
  $media_array->media_actions = '';
83
  }
app/main/controllers/media/RTMediaGroupFeatured.php CHANGED
@@ -22,7 +22,7 @@ class RTMediaGroupFeatured extends RTMediaUserInteraction {
22
  'single' => true,
23
  'repeatable' => false,
24
  'undoable' => true,
25
- 'icon_class' => 'dashicons dashicons-star-filled rtmicon',
26
  );
27
 
28
  $this->group_id = $group_id;
22
  'single' => true,
23
  'repeatable' => false,
24
  'undoable' => true,
25
+ 'icon_class' => 'dashicons dashicons-star-filled',
26
  );
27
 
28
  $this->group_id = $group_id;
app/main/controllers/media/RTMediaLoginPopup.php CHANGED
@@ -35,7 +35,7 @@ class RTMediaLoginPopup {
35
 
36
  function rtmedia_add_upload_album_button_popup() {
37
  if ( ! is_user_logged_in() ) {
38
- echo '<span><a href="#rtmedia-login-register-modal" class="primary rtmedia-upload-media-link rtmedia-modal-link" id="rtmedia-login-register-modal" title="' . apply_filters( 'rtm_album_upload_title_label', __( 'Upload Media', 'buddypress-media' ) ) . '"><i class="dashicons dashicons-upload rtmicon"></i>' . apply_filters( 'rtm_album_upload_label', __( 'Upload', 'buddypress-media' ) ) . '</a></span>';
39
  }
40
  }
41
 
35
 
36
  function rtmedia_add_upload_album_button_popup() {
37
  if ( ! is_user_logged_in() ) {
38
+ echo '<span><a href="#rtmedia-login-register-modal" class="primary rtmedia-upload-media-link rtmedia-modal-link" id="rtmedia-login-register-modal" title="' . apply_filters( 'rtm_album_upload_title_label', __( 'Upload Media', 'buddypress-media' ) ) . '"><i class="dashicons dashicons-upload"></i>' . apply_filters( 'rtm_album_upload_label', __( 'Upload', 'buddypress-media' ) ) . '</a></span>';
39
  }
40
  }
41
 
app/main/controllers/media/RTMediaMedia.php CHANGED
@@ -439,7 +439,7 @@ class RTMediaMedia {
439
  }
440
  }
441
  }
442
- if ( ! $core ) {
443
  wp_delete_attachment( $media[0]->media_id, true );
444
  }
445
  $status = $this->model->delete( array( 'id' => $id ) );
@@ -712,7 +712,7 @@ class RTMediaMedia {
712
  $activity_content = $activity->create_activity_html();
713
  $user = get_userdata( $media->media_author );
714
  $username = '<a href="' . esc_url( get_rtmedia_user_link( $media->media_author ) ) . '">' . esc_html( $user->display_name ) . '</a>';
715
- $count = count( $id );
716
  $media_const = 'RTMEDIA_' . strtoupper( $media->media_type );
717
  if ( $count > 1 ) {
718
  $media_const .= '_PLURAL';
439
  }
440
  }
441
  }
442
+ if ( ! $core && ! is_admin() ) {
443
  wp_delete_attachment( $media[0]->media_id, true );
444
  }
445
  $status = $this->model->delete( array( 'id' => $id ) );
712
  $activity_content = $activity->create_activity_html();
713
  $user = get_userdata( $media->media_author );
714
  $username = '<a href="' . esc_url( get_rtmedia_user_link( $media->media_author ) ) . '">' . esc_html( $user->display_name ) . '</a>';
715
+ $count = is_array( $id ) ? count( $id ) : 1 ;
716
  $media_const = 'RTMEDIA_' . strtoupper( $media->media_type );
717
  if ( $count > 1 ) {
718
  $media_const .= '_PLURAL';
app/main/controllers/media/RTMediaTags.php CHANGED
@@ -77,11 +77,14 @@ class RTMediaTags {
77
 
78
  $tagwriter->tag_data = $this->data;
79
 
80
- // write tags
81
- if ( $tagwriter->WriteTags() ) {
82
- return true;
83
- } else {
 
84
  throw new Exception( implode( ' : ', $tagwriter->errors ) );
 
 
85
  }
86
  }
87
 
@@ -145,7 +148,10 @@ class RTMediaTags {
145
  if ( isset( $this->duration_info[ $key ] ) ) {
146
  return $this->duration_info[ $key ];
147
  } else {
148
- return isset( $this->data[ $key ] ) ? $this->data[ $key ][0] : null;
 
 
 
149
  }
150
  }
151
  }
77
 
78
  $tagwriter->tag_data = $this->data;
79
 
80
+ // write tags.
81
+ try {
82
+ if ( $tagwriter->WriteTags() ) {
83
+ return true;
84
+ }
85
  throw new Exception( implode( ' : ', $tagwriter->errors ) );
86
+ } catch ( Exception $e ) {
87
+ return new WP_Error( 'tag_write_error', $e->getMessage() );
88
  }
89
  }
90
 
148
  if ( isset( $this->duration_info[ $key ] ) ) {
149
  return $this->duration_info[ $key ];
150
  } else {
151
+ if ( ! empty( $this->data[ $key ] ) && ! empty( $this->data[ $key ][0] ) ) {
152
+ return $this->data[ $key ][0];
153
+ }
154
+ return null;
155
  }
156
  }
157
  }
app/main/controllers/media/RTMediaUserInteraction.php CHANGED
@@ -215,8 +215,9 @@ class RTMediaUserInteraction {
215
  $icon = "<i class='" . esc_attr( $this->icon_class ) . "'></i>";
216
  }
217
  $button_start = '<form action="' . esc_url( $link ) . '">';
 
218
  $button = '<button type="submit" id="rtmedia-' . esc_attr( $this->action ) . '-button-' . esc_attr( $this->media->id ) . '" class="rtmedia-' . esc_attr( $this->action )
219
- . ' rtmedia-action-buttons button' . esc_attr( $disabled ) . '">' . $icon . '<span>' . apply_filters( 'rtmedia_' . $this->action . '_label_text', esc_html( $this->label ) ) . '</span></button>';
220
 
221
  //filter the button as required
222
  $button = apply_filters( 'rtmedia_' . $this->action . '_button_filter', $button );
215
  $icon = "<i class='" . esc_attr( $this->icon_class ) . "'></i>";
216
  }
217
  $button_start = '<form action="' . esc_url( $link ) . '">';
218
+ $button_label = apply_filters( 'rtmedia_' . $this->action . '_label_text', $this->label );
219
  $button = '<button type="submit" id="rtmedia-' . esc_attr( $this->action ) . '-button-' . esc_attr( $this->media->id ) . '" class="rtmedia-' . esc_attr( $this->action )
220
+ . ' rtmedia-action-buttons button' . esc_attr( $disabled ) . '" title="' . esc_attr( $button_label ) . '">' . $icon . '<span>' . esc_html( $button_label ) . '</span></button>';
221
 
222
  //filter the button as required
223
  $button = apply_filters( 'rtmedia_' . $this->action . '_button_filter', $button );
app/main/controllers/template/rtmedia-actions.php CHANGED
@@ -51,7 +51,7 @@ function rtmedia_image_editor_title( $type = 'photo' ) {
51
  global $rtmedia_query;
52
 
53
  if ( isset( $rtmedia_query->media[0]->media_type ) && 'photo' === $rtmedia_query->media[0]->media_type && 'photo' === $type ) {
54
- echo '<li><a href="#panel2" class="rtmedia-modify-image"><i class="dashicons dashicons-format-image rtmicon"></i>' . esc_html__( 'Image', 'buddypress-media' ) . '</a></li>';
55
  }
56
 
57
  }
@@ -150,7 +150,7 @@ function rtmedia_gallery_options() {
150
  if ( ! empty( $options ) ) {
151
  $options_start .= '<div class="click-nav rtm-media-options-list" id="rtm-media-options-list">
152
  <div class="no-js">
153
- <div class="clicker rtmedia-action-buttons"><i class="dashicons dashicons-admin-generic rtmicon"></i>' . apply_filters( 'rtm_gallery_option_label', __( 'Options', 'buddypress-media' ) ) . '</div>
154
  <ul class="rtm-options">';
155
 
156
  foreach ( $options as $action ) {
@@ -316,11 +316,11 @@ function add_upload_button() {
316
  $upload_string = apply_filters( 'rtmedia_upload_button_string', __( 'Upload', 'buddypress-media' ) );
317
 
318
  if ( function_exists( 'bp_is_user' ) && bp_is_user() && function_exists( 'bp_displayed_user_id' ) && bp_displayed_user_id() === get_current_user_id() ) {
319
- echo '<span class="primary rtmedia-upload-media-link" id="rtm_show_upload_ui" title="' . apply_filters( 'rtm_gallery_upload_title_label', __( 'Upload Media', 'buddypress-media' ) ) . '"><i class="dashicons dashicons-upload rtmicon"></i>' . apply_filters( 'rtm_gallery_upload_label', __( 'Upload', 'buddypress-media' ) ) . '</span>';
320
  } else {
321
  if ( function_exists( 'bp_is_group' ) && bp_is_group() ) {
322
  if ( can_user_upload_in_group() ) {
323
- echo '<span class="rtmedia-upload-media-link primary" id="rtm_show_upload_ui" title="' . apply_filters( 'rtm_gallery_upload_title_label', __( 'Upload Media', 'buddypress-media' ) ) . '"><i class="dashicons dashicons-upload rtmicon"></i>' . apply_filters( 'rtm_gallery_upload_label', __( 'Upload', 'buddypress-media' ) ) . '</span>';
324
  }
325
  }
326
  }
@@ -950,8 +950,8 @@ function add_search_filter( $attr = null ) {
950
  $html .= '</select>';
951
  }
952
 
953
- $html .= "<span id='media_search_remove' class='media_search_remove search_option'><i class='dashicons dashicons-no rtmicon'></i></span>";
954
- $html .= "<button type='submit' id='media_search' class='search_option'><i class='dashicons dashicons-search rtmicon'></i></button>";
955
  $html .= '</form>';
956
 
957
  /**
51
  global $rtmedia_query;
52
 
53
  if ( isset( $rtmedia_query->media[0]->media_type ) && 'photo' === $rtmedia_query->media[0]->media_type && 'photo' === $type ) {
54
+ echo '<li><a href="#panel2" class="rtmedia-modify-image"><i class="dashicons dashicons-format-image"></i>' . esc_html__( 'Image', 'buddypress-media' ) . '</a></li>';
55
  }
56
 
57
  }
150
  if ( ! empty( $options ) ) {
151
  $options_start .= '<div class="click-nav rtm-media-options-list" id="rtm-media-options-list">
152
  <div class="no-js">
153
+ <div class="clicker rtmedia-action-buttons"><i class="dashicons dashicons-admin-generic"></i>' . apply_filters( 'rtm_gallery_option_label', __( 'Options', 'buddypress-media' ) ) . '</div>
154
  <ul class="rtm-options">';
155
 
156
  foreach ( $options as $action ) {
316
  $upload_string = apply_filters( 'rtmedia_upload_button_string', __( 'Upload', 'buddypress-media' ) );
317
 
318
  if ( function_exists( 'bp_is_user' ) && bp_is_user() && function_exists( 'bp_displayed_user_id' ) && bp_displayed_user_id() === get_current_user_id() ) {
319
+ echo '<span class="primary rtmedia-upload-media-link" id="rtm_show_upload_ui" title="' . apply_filters( 'rtm_gallery_upload_title_label', __( 'Upload Media', 'buddypress-media' ) ) . '"><i class="dashicons dashicons-upload"></i>' . apply_filters( 'rtm_gallery_upload_label', __( 'Upload', 'buddypress-media' ) ) . '</span>';
320
  } else {
321
  if ( function_exists( 'bp_is_group' ) && bp_is_group() ) {
322
  if ( can_user_upload_in_group() ) {
323
+ echo '<span class="rtmedia-upload-media-link primary" id="rtm_show_upload_ui" title="' . apply_filters( 'rtm_gallery_upload_title_label', __( 'Upload Media', 'buddypress-media' ) ) . '"><i class="dashicons dashicons-upload"></i>' . apply_filters( 'rtm_gallery_upload_label', __( 'Upload', 'buddypress-media' ) ) . '</span>';
324
  }
325
  }
326
  }
950
  $html .= '</select>';
951
  }
952
 
953
+ $html .= "<span id='media_search_remove' class='media_search_remove search_option'><i class='dashicons dashicons-no'></i></span>";
954
+ $html .= "<button type='submit' id='media_search' class='search_option'><i class='dashicons dashicons-search'></i></button>";
955
  $html .= '</form>';
956
 
957
  /**
app/main/controllers/template/rtmedia-filters.php CHANGED
@@ -47,7 +47,7 @@ function rtmedia_create_album( $options ) {
47
  if ( true === $display ) {
48
  add_action( 'rtmedia_before_media_gallery', 'rtmedia_create_album_modal' );
49
 
50
- $options[] = "<a href='#rtmedia-create-album-modal' class='rtmedia-reveal-modal rtmedia-modal-link' title='" . esc_attr__( 'Create New Album', 'buddypress-media' ) . "'><i class='dashicons dashicons-plus-alt rtmicon'></i>" . esc_html__( 'Add Album', 'buddypress-media' ) . '</a>';
51
  }
52
 
53
  return $options;
@@ -79,8 +79,8 @@ function rtmedia_album_edit( $options ) {
79
 
80
  if ( isset( $rtmedia_query->media_query ) && isset( $rtmedia_query->media_query['album_id'] ) && ! in_array( intval( $rtmedia_query->media_query['album_id'] ), array_map( 'intval', rtmedia_get_site_option( 'rtmedia-global-albums' ) ), true ) ) {
81
  if ( rtmedia_is_album_editable() || is_rt_admin() ) {
82
- $options[] = "<a href='edit/' class='rtmedia-edit' title='" . esc_attr__( 'Edit Album', 'buddypress-media' ) . "' ><i class='rtmicon dashicons dashicons-edit'></i>" . esc_html__( 'Edit Album', 'buddypress-media' ) . '</a>';
83
- $options[] = '<form method="post" class="album-delete-form rtmedia-inline" action="delete/">' . wp_nonce_field( 'rtmedia_delete_album_' . $rtmedia_query->media_query['album_id'], 'rtmedia_delete_album_nonce' ) . '<button type="submit" name="album-delete" class="rtmedia-delete-album" title="' . esc_attr__( 'Delete Album', 'buddypress-media' ) . '"><i class="dashicons dashicons-trash rtmicon"></i>' . esc_html__( 'Delete Album', 'buddypress-media' ) . '</button></form>';
84
 
85
  if ( is_rtmedia_group_album() ) {
86
  $album_list = rtmedia_group_album_list();
@@ -282,7 +282,8 @@ function replace_src_with_transcoded_file_url( $html, $rtmedia_media ) {
282
  $final_file_url = wp_get_attachment_url( $attachment_id );
283
  }
284
 
285
- return preg_replace( '/src=["]([^"]+)["]/', "src=\"$final_file_url\"", $html );
 
286
 
287
  }
288
 
@@ -815,20 +816,6 @@ function rtmedia_model_query_columns( $columns ) {
815
 
816
  add_filter( 'rtmedia-model-query-columns', 'rtmedia_model_query_columns', 10, 1 );
817
 
818
- function rtmedia_comment_max_links_callback( $values, $option = '' ) {
819
- $new_values = $values;
820
- if ( apply_filters( 'rtmedia_comment_max_links', true ) && 'comment_max_links' == $option ) {
821
- $rtmedia_attached_files = filter_input( INPUT_POST, 'rtMedia_attached_files', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
822
- if ( is_array( $rtmedia_attached_files ) && ! empty( $rtmedia_attached_files[0] ) ) {
823
- if ( $new_values < 5 ) {
824
- $new_values = 5;
825
- }
826
- }
827
- }
828
- return $new_values;
829
- }
830
- add_filter( 'option_comment_max_links', 'rtmedia_comment_max_links_callback', 10, 2 );
831
-
832
  /**
833
  * add link for @mentions of the username in the comment or the activity section after the media delete or media is trancoder
834
  */
47
  if ( true === $display ) {
48
  add_action( 'rtmedia_before_media_gallery', 'rtmedia_create_album_modal' );
49
 
50
+ $options[] = "<a href='#rtmedia-create-album-modal' class='rtmedia-reveal-modal rtmedia-modal-link' title='" . esc_attr__( 'Create New Album', 'buddypress-media' ) . "'><i class='dashicons dashicons-plus-alt'></i>" . esc_html__( 'Add Album', 'buddypress-media' ) . '</a>';
51
  }
52
 
53
  return $options;
79
 
80
  if ( isset( $rtmedia_query->media_query ) && isset( $rtmedia_query->media_query['album_id'] ) && ! in_array( intval( $rtmedia_query->media_query['album_id'] ), array_map( 'intval', rtmedia_get_site_option( 'rtmedia-global-albums' ) ), true ) ) {
81
  if ( rtmedia_is_album_editable() || is_rt_admin() ) {
82
+ $options[] = "<a href='edit/' class='rtmedia-edit' title='" . esc_attr__( 'Edit Album', 'buddypress-media' ) . "' ><i class='dashicons dashicons-edit'></i>" . esc_html__( 'Edit Album', 'buddypress-media' ) . '</a>';
83
+ $options[] = '<form method="post" class="album-delete-form rtmedia-inline" action="delete/">' . wp_nonce_field( 'rtmedia_delete_album_' . $rtmedia_query->media_query['album_id'], 'rtmedia_delete_album_nonce' ) . '<button type="submit" name="album-delete" class="rtmedia-delete-album" title="' . esc_attr__( 'Delete Album', 'buddypress-media' ) . '"><i class="dashicons dashicons-trash"></i>' . esc_html__( 'Delete Album', 'buddypress-media' ) . '</button></form>';
84
 
85
  if ( is_rtmedia_group_album() ) {
86
  $album_list = rtmedia_group_album_list();
282
  $final_file_url = wp_get_attachment_url( $attachment_id );
283
  }
284
 
285
+ //Add timestamp to resolve conflict with cache media.
286
+ return preg_replace( '/src=["]([^"]+)["]/', 'src="' . $final_file_url . '?' . time() . '"', $html );
287
 
288
  }
289
 
816
 
817
  add_filter( 'rtmedia-model-query-columns', 'rtmedia_model_query_columns', 10, 1 );
818
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
819
  /**
820
  * add link for @mentions of the username in the comment or the activity section after the media delete or media is trancoder
821
  */
app/main/controllers/template/rtmedia-functions.php CHANGED
@@ -547,8 +547,11 @@ function rtmedia_media( $size_flag = true, $echo = true, $media_size = 'rt_media
547
  * Used `set_url_scheme` because `esc_url` breaks the image if there is special characters are there into image name.
548
  * Added by checking the code from "wp-admin/includes/media.php:2740".
549
  * Because in media library, it was not breaking.
 
 
550
  */
551
- $html = "<img src='" . set_url_scheme( $src[0] ) . "' alt='" . esc_attr( $rtmedia_media->post_name ) . "' />";
 
552
  } elseif ( 'video' === $rtmedia_media->media_type ) {
553
  $youtube_url = get_rtmedia_meta( $rtmedia_media->id, 'video_url_uploaded_from' );
554
  $height = $rtmedia->options['defaultSizes_video_singlePlayer_height'];
@@ -691,6 +694,9 @@ function rtmedia_image( $size = 'rt_media_thumbnail', $id = false, $recho = true
691
 
692
  $src = apply_filters( 'rtmedia_media_thumb', $src, $media_object->id, $media_object->media_type );
693
 
 
 
 
694
  if ( true === $recho ) {
695
  echo set_url_scheme( $src );
696
  } else {
@@ -1312,7 +1318,7 @@ function rmedia_single_comment( $comment, $count = false, $i = false ) {
1312
  $html .= '<div class="rtmedia-comment-extra">' . apply_filters( 'rtmedia_comment_extra', '', $comment ) . '</div>';
1313
 
1314
  if ( is_rt_admin() || ( isset( $comment['user_id'] ) && ( get_current_user_id() === intval( $comment['user_id'] ) || intval( $rtmedia_media->media_author ) === get_current_user_id() ) ) || apply_filters( 'rtmedia_allow_comment_delete', false ) ) { // show delete button for comment author and admins
1315
- $html .= '<i data-id="' . esc_attr( $comment['comment_ID'] ) . '" class = "rtmedia-delete-comment dashicons dashicons-no-alt rtmicon" title="' . esc_attr__( 'Delete Comment', 'buddypress-media' ) . '"></i>';
1316
  }
1317
 
1318
  $html .= '<div class="clear"></div></div></div></li>';
@@ -2880,7 +2886,7 @@ function show_rtmedia_like_counts() {
2880
  }
2881
  ?>
2882
  <div class='rtmedia-like-info <?php echo $class; ?>'>
2883
- <i class="rtmicon-thumbs-up rtmicon-fw"></i>
2884
  <span class="rtmedia-like-counter-wrap">
2885
  <?php
2886
  if ( class_exists( 'RTMediaLike' ) && function_exists( 'rtmedia_who_like_html' ) ) {
@@ -3063,27 +3069,27 @@ function get_rtmedia_privacy_symbol( $rtmedia_id = false ) {
3063
  switch ( $actions[0]->privacy ) {
3064
  case 0: // public
3065
  $title = esc_html__( 'Public', 'buddypress-media' );
3066
- $icon = 'dashicons dashicons-admin-site rtmicon';
3067
 
3068
  break;
3069
  case 20: // users
3070
  $title = esc_html__( 'All members', 'buddypress-media' );
3071
- $icon = 'dashicons dashicons-groups rtmicon';
3072
 
3073
  break;
3074
  case 40: // friends
3075
  $title = esc_html__( 'Your friends', 'buddypress-media' );
3076
- $icon = 'dashicons dashicons-networking rtmicon';
3077
 
3078
  break;
3079
  case 60: // private
3080
  $title = esc_html__( 'Only you', 'buddypress-media' );
3081
- $icon = 'dashicons dashicons-lock rtmicon';
3082
 
3083
  break;
3084
  case 80: // private
3085
  $title = esc_html__( 'Blocked temporarily', 'buddypress-media' );
3086
- $icon = 'dashicons dashicons-dismiss rtmicon';
3087
 
3088
  break;
3089
  }
547
  * Used `set_url_scheme` because `esc_url` breaks the image if there is special characters are there into image name.
548
  * Added by checking the code from "wp-admin/includes/media.php:2740".
549
  * Because in media library, it was not breaking.
550
+ *
551
+ * Add timestamp to resolve conflict with cache image.
552
  */
553
+ $html = "<img src='" . set_url_scheme( $src[0]. '?' . time() ) . "' alt='" . esc_attr( $rtmedia_media->post_name ) . "' />";
554
+
555
  } elseif ( 'video' === $rtmedia_media->media_type ) {
556
  $youtube_url = get_rtmedia_meta( $rtmedia_media->id, 'video_url_uploaded_from' );
557
  $height = $rtmedia->options['defaultSizes_video_singlePlayer_height'];
694
 
695
  $src = apply_filters( 'rtmedia_media_thumb', $src, $media_object->id, $media_object->media_type );
696
 
697
+ //Added timestamp because conflict with cache image.
698
+ $src = $src . '?' . time();
699
+
700
  if ( true === $recho ) {
701
  echo set_url_scheme( $src );
702
  } else {
1318
  $html .= '<div class="rtmedia-comment-extra">' . apply_filters( 'rtmedia_comment_extra', '', $comment ) . '</div>';
1319
 
1320
  if ( is_rt_admin() || ( isset( $comment['user_id'] ) && ( get_current_user_id() === intval( $comment['user_id'] ) || intval( $rtmedia_media->media_author ) === get_current_user_id() ) ) || apply_filters( 'rtmedia_allow_comment_delete', false ) ) { // show delete button for comment author and admins
1321
+ $html .= '<i data-id="' . esc_attr( $comment['comment_ID'] ) . '" class = "rtmedia-delete-comment dashicons dashicons-no-alt" title="' . esc_attr__( 'Delete Comment', 'buddypress-media' ) . '"></i>';
1322
  }
1323
 
1324
  $html .= '<div class="clear"></div></div></div></li>';
2886
  }
2887
  ?>
2888
  <div class='rtmedia-like-info <?php echo $class; ?>'>
2889
+ <i class="dashicons dashicons-thumbs-up"></i>
2890
  <span class="rtmedia-like-counter-wrap">
2891
  <?php
2892
  if ( class_exists( 'RTMediaLike' ) && function_exists( 'rtmedia_who_like_html' ) ) {
3069
  switch ( $actions[0]->privacy ) {
3070
  case 0: // public
3071
  $title = esc_html__( 'Public', 'buddypress-media' );
3072
+ $icon = 'dashicons dashicons-admin-site';
3073
 
3074
  break;
3075
  case 20: // users
3076
  $title = esc_html__( 'All members', 'buddypress-media' );
3077
+ $icon = 'dashicons dashicons-groups';
3078
 
3079
  break;
3080
  case 40: // friends
3081
  $title = esc_html__( 'Your friends', 'buddypress-media' );
3082
+ $icon = 'dashicons dashicons-networking';
3083
 
3084
  break;
3085
  case 60: // private
3086
  $title = esc_html__( 'Only you', 'buddypress-media' );
3087
+ $icon = 'dashicons dashicons-lock';
3088
 
3089
  break;
3090
  case 80: // private
3091
  $title = esc_html__( 'Blocked temporarily', 'buddypress-media' );
3092
+ $icon = 'dashicons dashicons-dismiss';
3093
 
3094
  break;
3095
  }
app/main/controllers/upload/RTMediaUploadView.php CHANGED
@@ -48,10 +48,10 @@ class RTMediaUploadView {
48
  } elseif ( is_rtmedia_album_enable() && $rtmedia_query && is_rtmedia_gallery() ) {
49
 
50
  if ( isset( $rtmedia_query->query['context'] ) && 'profile' === $rtmedia_query->query['context'] ) {
51
- $album = '<span> <label> <i class="dashicons dashicons-format-gallery rtmicon"></i>' . esc_html__( 'Album', 'buddypress-media' ) . ': </label><select name="album" class="rtmedia-user-album-list">' . rtmedia_user_album_list() . '</select></span>';
52
  }
53
  if ( isset( $rtmedia_query->query['context'] ) && 'group' === $rtmedia_query->query['context'] ) {
54
- $album = '<span> <label> <i class="dashicons dashicons-format-gallery rtmicon"></i>' . esc_html__( 'Album', 'buddypress-media' ) . ': </label><select name="album" class="rtmedia-user-album-list">' . rtmedia_group_album_list() . '</select></span>';
55
  }
56
  }
57
  }
@@ -94,7 +94,7 @@ class RTMediaUploadView {
94
  $up_privacy = new RTMediaPrivacy( false );
95
  $up_privacy = $up_privacy->select_privacy_ui( false, 'rtSelectPrivacy' );
96
  if ( $up_privacy ) {
97
- $privacy = "<span> <label for='privacy'> <i class='dashicons dashicons-visibility rtmicon'></i>" . esc_html__( 'Privacy:', 'buddypress-media' ) . '</label>' . $up_privacy . '</span>';
98
  }
99
  }
100
  }
@@ -106,7 +106,7 @@ class RTMediaUploadView {
106
  'content' => '<div class="rtm-upload-tab-content" data-id="rtm-upload-tab">'
107
  . apply_filters( 'rtmedia_uploader_before_select_files', '' )
108
  . '<div class="rtm-select-files"><input id="' . apply_filters( 'rtmedia_upload_button_id', 'rtMedia-upload-button' ) . '" value="' . esc_attr__( 'Select your files', 'buddypress-media' ) . '" type="button" class="rtmedia-upload-input rtmedia-file" />'
109
- . '<span class="rtm-seperator">' . esc_html__( 'or', 'buddypress-media' ) . '</span><span class="drag-drop-info">' . esc_html__( 'Drop your files here', 'buddypress-media' ) . '</span> <i class="rtm-file-size-limit rtmicon-info-circle rtmicon-fw"></i></div>'
110
  . apply_filters( 'rtmedia_uploader_after_select_files', '' )
111
  . '</div>',
112
  ),
48
  } elseif ( is_rtmedia_album_enable() && $rtmedia_query && is_rtmedia_gallery() ) {
49
 
50
  if ( isset( $rtmedia_query->query['context'] ) && 'profile' === $rtmedia_query->query['context'] ) {
51
+ $album = '<span> <label> <i class="dashicons dashicons-format-gallery"></i>' . esc_html__( 'Album', 'buddypress-media' ) . ': </label><select name="album" class="rtmedia-user-album-list">' . rtmedia_user_album_list() . '</select></span>';
52
  }
53
  if ( isset( $rtmedia_query->query['context'] ) && 'group' === $rtmedia_query->query['context'] ) {
54
+ $album = '<span> <label> <i class="dashicons dashicons-format-gallery"></i>' . esc_html__( 'Album', 'buddypress-media' ) . ': </label><select name="album" class="rtmedia-user-album-list">' . rtmedia_group_album_list() . '</select></span>';
55
  }
56
  }
57
  }
94
  $up_privacy = new RTMediaPrivacy( false );
95
  $up_privacy = $up_privacy->select_privacy_ui( false, 'rtSelectPrivacy' );
96
  if ( $up_privacy ) {
97
+ $privacy = "<span> <label for='privacy'> <i class='dashicons dashicons-visibility'></i>" . esc_html__( 'Privacy:', 'buddypress-media' ) . '</label>' . $up_privacy . '</span>';
98
  }
99
  }
100
  }
106
  'content' => '<div class="rtm-upload-tab-content" data-id="rtm-upload-tab">'
107
  . apply_filters( 'rtmedia_uploader_before_select_files', '' )
108
  . '<div class="rtm-select-files"><input id="' . apply_filters( 'rtmedia_upload_button_id', 'rtMedia-upload-button' ) . '" value="' . esc_attr__( 'Select your files', 'buddypress-media' ) . '" type="button" class="rtmedia-upload-input rtmedia-file" />'
109
+ . '<span class="rtm-seperator">' . esc_html__( 'or', 'buddypress-media' ) . '</span><span class="drag-drop-info">' . esc_html__( 'Drop your files here', 'buddypress-media' ) . '</span> <i class="rtm-file-size-limit dashicons dashicons-info"></i></div>'
110
  . apply_filters( 'rtmedia_uploader_after_select_files', '' )
111
  . '</div>',
112
  ),
index.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: rtMedia for WordPress, BuddyPress and bbPress
4
  Plugin URI: https://rtmedia.io/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
5
  Description: This plugin adds missing media rich features like photos, videos and audio uploading to BuddyPress which are essential if you are building social network, seriously!
6
- Version: 4.5.6
7
  Author: rtCamp
8
  Text Domain: buddypress-media
9
  Author URI: http://rtcamp.com/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
@@ -22,7 +22,7 @@ if ( ! defined( 'RTMEDIA_VERSION' ) ) {
22
  * The version of the plugin
23
  *
24
  */
25
- define( 'RTMEDIA_VERSION', '4.5.6' );
26
  }
27
 
28
  if ( ! defined( 'RTMEDIA_PATH' ) ) {
3
  Plugin Name: rtMedia for WordPress, BuddyPress and bbPress
4
  Plugin URI: https://rtmedia.io/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
5
  Description: This plugin adds missing media rich features like photos, videos and audio uploading to BuddyPress which are essential if you are building social network, seriously!
6
+ Version: 4.5.7
7
  Author: rtCamp
8
  Text Domain: buddypress-media
9
  Author URI: http://rtcamp.com/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
22
  * The version of the plugin
23
  *
24
  */
25
+ define( 'RTMEDIA_VERSION', '4.5.7' );
26
  }
27
 
28
  if ( ! defined( 'RTMEDIA_PATH' ) ) {
languages/buddypress-media.po CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the same license as the rtMedia for WordPress, BuddyPress and bbPress package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: rtMedia for WordPress, BuddyPress and bbPress 4.5.6\n"
6
  "Report-Msgid-Bugs-To: https://rtmedia.io/support/\n"
7
- "POT-Creation-Date: 2019-02-14 12:28:32+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -22,7 +22,7 @@ msgstr ""
22
  "X-Poedit-SearchPath-0: .\n"
23
  "X-Poedit-Bookmarks: \n"
24
  "X-Textdomain-Support: yes\n"
25
- "X-Generator: grunt-wp-i18n1.0.2\n"
26
 
27
  #: app/admin/RTMediaAdmin.php:148
28
  msgid ""
2
  # This file is distributed under the same license as the rtMedia for WordPress, BuddyPress and bbPress package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: rtMedia for WordPress, BuddyPress and bbPress 4.5.7\n"
6
  "Report-Msgid-Bugs-To: https://rtmedia.io/support/\n"
7
+ "POT-Creation-Date: 2019-06-10 12:30:20+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
22
  "X-Poedit-SearchPath-0: .\n"
23
  "X-Poedit-Bookmarks: \n"
24
  "X-Textdomain-Support: yes\n"
25
+ "X-Generator: grunt-wp-i18n 1.0.3\n"
26
 
27
  #: app/admin/RTMediaAdmin.php:148
28
  msgid ""
lib/getid3/extension.cache.dbm.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
  // //
9
  // extension.cache.dbm.php - part of getID3() //
10
  // Please see readme.txt for more information //
@@ -72,9 +72,37 @@
72
 
73
  class getID3_cached_dbm extends getID3
74
  {
75
-
76
- // public: constructor - see top of this file for cache type and cache_options
77
- public function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  // Check for dba extension
80
  if (!extension_loaded('dba')) {
@@ -141,7 +169,9 @@ class getID3_cached_dbm extends getID3
141
 
142
 
143
 
144
- // public: destructor
 
 
145
  public function __destruct() {
146
 
147
  // Close dbm file
@@ -156,7 +186,11 @@ class getID3_cached_dbm extends getID3
156
 
157
 
158
 
159
- // public: clear cache
 
 
 
 
160
  public function clear_cache() {
161
 
162
  // Close dbm file
@@ -178,8 +212,16 @@ class getID3_cached_dbm extends getID3
178
 
179
 
180
 
181
- // public: analyze file
182
- public function analyze($filename) {
 
 
 
 
 
 
 
 
183
 
184
  if (file_exists($filename)) {
185
 
@@ -199,7 +241,7 @@ class getID3_cached_dbm extends getID3
199
  $result = parent::analyze($filename);
200
 
201
  // Save result
202
- if (file_exists($filename)) {
203
  dba_insert($key, serialize($result), $this->dba);
204
  }
205
 
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
 
8
  // //
9
  // extension.cache.dbm.php - part of getID3() //
10
  // Please see readme.txt for more information //
72
 
73
  class getID3_cached_dbm extends getID3
74
  {
75
+ /**
76
+ * @var resource
77
+ */
78
+ private $dba;
79
+
80
+ /**
81
+ * @var resource|bool
82
+ */
83
+ private $lock;
84
+
85
+ /**
86
+ * @var string
87
+ */
88
+ private $cache_type;
89
+
90
+ /**
91
+ * @var string
92
+ */
93
+ private $dbm_filename;
94
+
95
+ /**
96
+ * constructor - see top of this file for cache type and cache_options
97
+ *
98
+ * @param string $cache_type
99
+ * @param string $dbm_filename
100
+ * @param string $lock_filename
101
+ *
102
+ * @throws Exception
103
+ * @throws getid3_exception
104
+ */
105
+ public function __construct($cache_type, $dbm_filename, $lock_filename) {
106
 
107
  // Check for dba extension
108
  if (!extension_loaded('dba')) {
169
 
170
 
171
 
172
+ /**
173
+ * destructor
174
+ */
175
  public function __destruct() {
176
 
177
  // Close dbm file
186
 
187
 
188
 
189
+ /**
190
+ * clear cache
191
+ *
192
+ * @throws Exception
193
+ */
194
  public function clear_cache() {
195
 
196
  // Close dbm file
212
 
213
 
214
 
215
+ /**
216
+ * clear cache
217
+ *
218
+ * @param string $filename
219
+ * @param int $filesize
220
+ * @param string $original_filename
221
+ *
222
+ * @return mixed
223
+ */
224
+ public function analyze($filename, $filesize=null, $original_filename='') {
225
 
226
  if (file_exists($filename)) {
227
 
241
  $result = parent::analyze($filename);
242
 
243
  // Save result
244
+ if (isset($key) && file_exists($filename)) {
245
  dba_insert($key, serialize($result), $this->dba);
246
  }
247
 
lib/getid3/extension.cache.mysql.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
  // //
9
  // extension.cache.mysql.php - part of getID3() //
10
  // Please see readme.txt for more information //
@@ -73,14 +73,35 @@
73
 
74
  class getID3_cached_mysql extends getID3
75
  {
76
-
77
- // private vars
 
78
  private $cursor;
79
- private $connection;
80
 
 
 
 
 
81
 
82
- // public: constructor - see top of this file for cache type and cache_options
83
- public function getID3_cached_mysql($host, $database, $username, $password, $table='getid3_cache') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
  // Check for mysql support
86
  if (!function_exists('mysql_pconnect')) {
@@ -124,7 +145,9 @@ class getID3_cached_mysql extends getID3
124
 
125
 
126
 
127
- // public: clear cache
 
 
128
  public function clear_cache() {
129
 
130
  $this->cursor = mysql_query('DELETE FROM `'.mysql_real_escape_string($this->table).'`', $this->connection);
@@ -133,9 +156,18 @@ class getID3_cached_mysql extends getID3
133
 
134
 
135
 
136
- // public: analyze file
 
 
 
 
 
 
 
 
137
  public function analyze($filename, $filesize=null, $original_filename='') {
138
 
 
139
  if (file_exists($filename)) {
140
 
141
  // Short-hands
@@ -174,16 +206,20 @@ class getID3_cached_mysql extends getID3
174
 
175
 
176
 
177
- // private: (re)create sql table
 
 
 
 
178
  private function create_table($drop=false) {
179
 
180
  $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
181
- $SQLquery .= '`filename` VARCHAR(500) NOT NULL DEFAULT \'\'';
182
  $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
183
  $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
184
  $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
185
  $SQLquery .= ', `value` LONGTEXT NOT NULL';
186
- $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM';
187
  $this->cursor = mysql_query($SQLquery, $this->connection);
188
  echo mysql_error($this->connection);
189
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
 
8
  // //
9
  // extension.cache.mysql.php - part of getID3() //
10
  // Please see readme.txt for more information //
73
 
74
  class getID3_cached_mysql extends getID3
75
  {
76
+ /**
77
+ * @var resource
78
+ */
79
  private $cursor;
 
80
 
81
+ /**
82
+ * @var resource
83
+ */
84
+ private $connection;
85
 
86
+ /**
87
+ * @var string
88
+ */
89
+ private $table;
90
+
91
+
92
+ /**
93
+ * constructor - see top of this file for cache type and cache_options
94
+ *
95
+ * @param string $host
96
+ * @param string $database
97
+ * @param string $username
98
+ * @param string $password
99
+ * @param string $table
100
+ *
101
+ * @throws Exception
102
+ * @throws getid3_exception
103
+ */
104
+ public function __construct($host, $database, $username, $password, $table='getid3_cache') {
105
 
106
  // Check for mysql support
107
  if (!function_exists('mysql_pconnect')) {
145
 
146
 
147
 
148
+ /**
149
+ * clear cache
150
+ */
151
  public function clear_cache() {
152
 
153
  $this->cursor = mysql_query('DELETE FROM `'.mysql_real_escape_string($this->table).'`', $this->connection);
156
 
157
 
158
 
159
+ /**
160
+ * analyze file
161
+ *
162
+ * @param string $filename
163
+ * @param int $filesize
164
+ * @param string $original_filename
165
+ *
166
+ * @return mixed
167
+ */
168
  public function analyze($filename, $filesize=null, $original_filename='') {
169
 
170
+ $filetime = 0;
171
  if (file_exists($filename)) {
172
 
173
  // Short-hands
206
 
207
 
208
 
209
+ /**
210
+ * (re)create sql table
211
+ *
212
+ * @param bool $drop
213
+ */
214
  private function create_table($drop=false) {
215
 
216
  $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
217
+ $SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
218
  $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
219
  $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
220
  $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
221
  $SQLquery .= ', `value` LONGTEXT NOT NULL';
222
+ $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`))';
223
  $this->cursor = mysql_query($SQLquery, $this->connection);
224
  echo mysql_error($this->connection);
225
  }
lib/getid3/extension.cache.mysqli.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /////////////////////////////////////////////////////////////////
4
+ /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // //
9
+ // extension.cache.mysqli.php - part of getID3() //
10
+ // Please see readme.txt for more information //
11
+ // //
12
+ /////////////////////////////////////////////////////////////////
13
+ // //
14
+ // This extension written by Allan Hansen <ahØartemis*dk> //
15
+ // Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
16
+ // ///
17
+ /////////////////////////////////////////////////////////////////
18
+
19
+
20
+ /**
21
+ * This is a caching extension for getID3(). It works the exact same
22
+ * way as the getID3 class, but return cached information very fast
23
+ *
24
+ * Example: (see also demo.cache.mysql.php in /demo/)
25
+ *
26
+ * Normal getID3 usage (example):
27
+ *
28
+ * require_once 'getid3/getid3.php';
29
+ * $getID3 = new getID3;
30
+ * $getID3->encoding = 'UTF-8';
31
+ * $info1 = $getID3->analyze('file1.flac');
32
+ * $info2 = $getID3->analyze('file2.wv');
33
+ *
34
+ * getID3_cached usage:
35
+ *
36
+ * require_once 'getid3/getid3.php';
37
+ * require_once 'getid3/getid3/extension.cache.mysqli.php';
38
+ * // 5th parameter (tablename) is optional, default is 'getid3_cache'
39
+ * $getID3 = new getID3_cached_mysqli('localhost', 'database', 'username', 'password', 'tablename');
40
+ * $getID3->encoding = 'UTF-8';
41
+ * $info1 = $getID3->analyze('file1.flac');
42
+ * $info2 = $getID3->analyze('file2.wv');
43
+ *
44
+ *
45
+ * Supported Cache Types (this extension)
46
+ *
47
+ * SQL Databases:
48
+ *
49
+ * cache_type cache_options
50
+ * -------------------------------------------------------------------
51
+ * mysqli host, database, username, password
52
+ *
53
+ *
54
+ * DBM-Style Databases: (use extension.cache.dbm)
55
+ *
56
+ * cache_type cache_options
57
+ * -------------------------------------------------------------------
58
+ * gdbm dbm_filename, lock_filename
59
+ * ndbm dbm_filename, lock_filename
60
+ * db2 dbm_filename, lock_filename
61
+ * db3 dbm_filename, lock_filename
62
+ * db4 dbm_filename, lock_filename (PHP5 required)
63
+ *
64
+ * PHP must have write access to both dbm_filename and lock_filename.
65
+ *
66
+ *
67
+ * Recommended Cache Types
68
+ *
69
+ * Infrequent updates, many reads any DBM
70
+ * Frequent updates mysqli
71
+ */
72
+
73
+ class getID3_cached_mysqli extends getID3
74
+ {
75
+ /**
76
+ * @var mysqli
77
+ */
78
+ private $mysqli;
79
+
80
+ /**
81
+ * @var mysqli_result
82
+ */
83
+ private $cursor;
84
+
85
+ /**
86
+ * @var string
87
+ */
88
+ private $table;
89
+
90
+
91
+ /**
92
+ * constructor - see top of this file for cache type and cache_options
93
+ *
94
+ * @param string $host
95
+ * @param string $database
96
+ * @param string $username
97
+ * @param string $password
98
+ * @param string $table
99
+ *
100
+ * @throws Exception
101
+ * @throws getid3_exception
102
+ */
103
+ public function __construct($host, $database, $username, $password, $table='getid3_cache') {
104
+
105
+ // Check for mysqli support
106
+ if (!function_exists('mysqli_connect')) {
107
+ throw new Exception('PHP not compiled with mysqli support.');
108
+ }
109
+
110
+ // Connect to database
111
+ $this->mysqli = new mysqli($host, $username, $password);
112
+ if (!$this->mysqli) {
113
+ throw new Exception('mysqli_connect() failed - check permissions and spelling.');
114
+ }
115
+
116
+ // Select database
117
+ if (!$this->mysqli->select_db($database)) {
118
+ throw new Exception('Cannot use database '.$database);
119
+ }
120
+
121
+ // Set table
122
+ $this->table = $table;
123
+
124
+ // Create cache table if not exists
125
+ $this->create_table();
126
+
127
+ // Check version number and clear cache if changed
128
+ $version = '';
129
+ $SQLquery = 'SELECT `value`';
130
+ $SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
131
+ $SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string(getID3::VERSION).'\')';
132
+ $SQLquery .= ' AND (`filesize` = -1)';
133
+ $SQLquery .= ' AND (`filetime` = -1)';
134
+ $SQLquery .= ' AND (`analyzetime` = -1)';
135
+ if ($this->cursor = $this->mysqli->query($SQLquery)) {
136
+ list($version) = $this->cursor->fetch_array();
137
+ }
138
+ if ($version != getID3::VERSION) {
139
+ $this->clear_cache();
140
+ }
141
+
142
+ parent::__construct();
143
+ }
144
+
145
+
146
+ /**
147
+ * clear cache
148
+ */
149
+ public function clear_cache() {
150
+ $this->mysqli->query('DELETE FROM `'.$this->mysqli->real_escape_string($this->table).'`');
151
+ $this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
152
+ }
153
+
154
+
155
+ /**
156
+ * analyze file
157
+ *
158
+ * @param string $filename
159
+ * @param int $filesize
160
+ * @param string $original_filename
161
+ *
162
+ * @return mixed
163
+ */
164
+ public function analyze($filename, $filesize=null, $original_filename='') {
165
+
166
+ $filetime = 0;
167
+ if (file_exists($filename)) {
168
+
169
+ // Short-hands
170
+ $filetime = filemtime($filename);
171
+ $filesize = filesize($filename);
172
+
173
+ // Lookup file
174
+ $SQLquery = 'SELECT `value`';
175
+ $SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
176
+ $SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string($filename).'\')';
177
+ $SQLquery .= ' AND (`filesize` = \''.$this->mysqli->real_escape_string($filesize).'\')';
178
+ $SQLquery .= ' AND (`filetime` = \''.$this->mysqli->real_escape_string($filetime).'\')';
179
+ $this->cursor = $this->mysqli->query($SQLquery);
180
+ if ($this->cursor->num_rows > 0) {
181
+ // Hit
182
+ list($result) = $this->cursor->fetch_array();
183
+ return unserialize(base64_decode($result));
184
+ }
185
+ }
186
+
187
+ // Miss
188
+ $analysis = parent::analyze($filename, $filesize, $original_filename);
189
+
190
+ // Save result
191
+ if (file_exists($filename)) {
192
+ $SQLquery = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
193
+ $SQLquery .= '\''.$this->mysqli->real_escape_string($filename).'\'';
194
+ $SQLquery .= ', \''.$this->mysqli->real_escape_string($filesize).'\'';
195
+ $SQLquery .= ', \''.$this->mysqli->real_escape_string($filetime).'\'';
196
+ $SQLquery .= ', \''.$this->mysqli->real_escape_string(time() ).'\'';
197
+ $SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\')';
198
+ $this->cursor = $this->mysqli->query($SQLquery);
199
+ }
200
+ return $analysis;
201
+ }
202
+
203
+
204
+ /**
205
+ * (re)create mysqli table
206
+ *
207
+ * @param bool $drop
208
+ */
209
+ private function create_table($drop=false) {
210
+ $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.$this->mysqli->real_escape_string($this->table).'` (';
211
+ $SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
212
+ $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
213
+ $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
214
+ $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
215
+ $SQLquery .= ', `value` LONGTEXT NOT NULL';
216
+ $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`))';
217
+ $this->cursor = $this->mysqli->query($SQLquery);
218
+ echo $this->mysqli->error;
219
+ }
220
+ }
lib/getid3/extension.cache.sqlite3.php CHANGED
@@ -1,21 +1,27 @@
1
  <?php
2
- /////////////////////////////////////////////////////////////////////////////////
3
- /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////////////////////
8
- /// //
9
- // extension.cache.sqlite3.php - part of getID3() //
10
- // Please see readme.txt for more information //
11
- // ///
12
- /////////////////////////////////////////////////////////////////////////////////
13
- /// //
14
- // MySQL extension written by Allan Hansen <ahØartemis*dk> //
15
- // Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
16
- // MySQL extension was reworked for SQLite3 by Karl G. Holz <newaeonØmac*com> //
17
- // ///
18
- /////////////////////////////////////////////////////////////////////////////////
 
 
 
 
 
 
19
  /**
20
  * This is a caching extension for getID3(). It works the exact same
21
  * way as the getID3 class, but return cached information much faster
@@ -89,14 +95,35 @@
89
  *
90
  *
91
  */
92
- class getID3_cached_sqlite3 extends getID3 {
 
 
 
 
 
 
 
93
 
94
  /**
95
- * __construct()
96
- * @param string $table holds name of sqlite table
97
- * @return type
98
- */
 
 
 
 
 
 
 
 
 
99
  public function __construct($table='getid3_cache', $hide=false) {
 
 
 
 
 
100
  $this->table = $table; // Set table
101
  $file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite';
102
  if ($hide) {
@@ -106,7 +133,7 @@ class getID3_cached_sqlite3 extends getID3 {
106
  $db = $this->db;
107
  $this->create_table(); // Create cache table if not exists
108
  $version = '';
109
- $sql = $this->version_check;
110
  $stmt = $db->prepare($sql);
111
  $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
112
  $result = $stmt->execute();
@@ -114,39 +141,27 @@ class getID3_cached_sqlite3 extends getID3 {
114
  if ($version != getID3::VERSION) { // Check version number and clear cache if changed
115
  $this->clear_cache();
116
  }
117
- return parent::__construct();
118
  }
119
 
120
  /**
121
- * close the database connection
122
- */
123
  public function __destruct() {
124
  $db=$this->db;
125
  $db->close();
126
  }
127
 
128
  /**
129
- * hold the sqlite db
130
- * @var SQLite Resource
131
- */
132
- private $db;
133
-
134
- /**
135
- * table to use for caching
136
- * @var string $table
137
- */
138
- private $table;
139
-
140
- /**
141
- * clear the cache
142
- * @access private
143
- * @return type
144
- */
145
  private function clear_cache() {
146
  $db = $this->db;
147
- $sql = $this->delete_cache;
148
  $db->exec($sql);
149
- $sql = $this->set_version;
150
  $stmt = $db->prepare($sql);
151
  $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
152
  $stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT);
@@ -155,72 +170,77 @@ class getID3_cached_sqlite3 extends getID3 {
155
  }
156
 
157
  /**
158
- * analyze file and cache them, if cached pull from the db
159
- * @param type $filename
160
- * @return boolean
161
- */
 
 
 
 
162
  public function analyze($filename, $filesize=null, $original_filename='') {
163
  if (!file_exists($filename)) {
164
  return false;
165
  }
166
  // items to track for caching
167
  $filetime = filemtime($filename);
168
- $filesize = filesize($filename);
169
  // this will be saved for a quick directory lookup of analized files
170
  // ... why do 50 seperate sql quries when you can do 1 for the same result
171
  $dirname = dirname($filename);
172
  // Lookup file
173
  $db = $this->db;
174
- $sql = $this->get_id3_data;
175
  $stmt = $db->prepare($sql);
176
- $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
177
- $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
178
- $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
179
  $res = $stmt->execute();
180
  list($result) = $res->fetchArray();
181
  if (count($result) > 0 ) {
182
  return unserialize(base64_decode($result));
183
  }
184
  // if it hasn't been analyzed before, then do it now
185
- $analysis = parent::analyze($filename, $filesize=null, $original_filename='');
186
  // Save result
187
- $sql = $this->cache_file;
188
  $stmt = $db->prepare($sql);
189
- $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
190
- $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
191
- $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
192
- $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
193
- $stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
194
- $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
195
  $res = $stmt->execute();
196
  return $analysis;
197
  }
198
 
199
  /**
200
- * create data base table
201
- * this is almost the same as MySQL, with the exception of the dirname being added
202
- * @return type
203
- */
 
204
  private function create_table() {
205
  $db = $this->db;
206
- $sql = $this->make_table;
207
  return $db->exec($sql);
208
  }
209
 
210
  /**
211
- * get cached directory
212
- *
213
- * This function is not in the MySQL extention, it's ment to speed up requesting multiple files
214
- * which is ideal for podcasting, playlists, etc.
215
- *
216
- * @access public
217
- * @param string $dir directory to search the cache database for
218
- * @return array return an array of matching id3 data
219
- */
220
  public function get_cached_dir($dir) {
221
  $db = $this->db;
222
  $rows = array();
223
- $sql = $this->get_cached_dir;
224
  $stmt = $db->prepare($sql);
225
  $stmt->bindValue(':dirname', $dir, SQLITE3_TEXT);
226
  $res = $stmt->execute();
@@ -231,12 +251,15 @@ class getID3_cached_sqlite3 extends getID3 {
231
  }
232
 
233
  /**
234
- * use the magical __get() for sql queries
235
- *
236
- * access as easy as $this->{case name}, returns NULL if query is not found
237
- */
238
- public function __get($name) {
239
- switch($name) {
 
 
 
240
  case 'version_check':
241
  return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
242
  break;
@@ -253,14 +276,28 @@ class getID3_cached_sqlite3 extends getID3 {
253
  return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
254
  break;
255
  case 'make_table':
256
- //return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname VARCHAR(255) NOT NULL DEFAULT '', filesize INT(11) NOT NULL DEFAULT '0', filetime INT(11) NOT NULL DEFAULT '0', analyzetime INT(11) NOT NULL DEFAULT '0', val text not null, PRIMARY KEY (filename, filesize, filetime))";
257
  return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
258
  break;
259
  case 'get_cached_dir':
260
  return "SELECT val FROM $this->table WHERE dirname = :dirname";
261
  break;
 
 
262
  }
263
- return null;
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  }
265
 
266
  }
1
  <?php
2
+ /////////////////////////////////////////////////////////////////
3
+ /// getID3() by James Heinrich <info@getid3.org> //
4
+ // available at https://github.com/JamesHeinrich/getID3 //
5
+ // or https://www.getid3.org //
6
+ // or http://getid3.sourceforge.net //
7
+ // //
8
+ // extension.cache.mysqli.php - part of getID3() //
9
+ // Please see readme.txt for more information //
10
+ // //
11
+ /////////////////////////////////////////////////////////////////
12
+ // //
13
+ // extension.cache.sqlite3.php - part of getID3() //
14
+ // Please see readme.txt for more information //
15
+ // //
16
+ /////////////////////////////////////////////////////////////////
17
+ /// //
18
+ // MySQL extension written by Allan Hansen <ahØartemis*dk> //
19
+ // Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
20
+ // MySQL extension was reworked for SQLite3 by //
21
+ // Karl G. Holz <newaeonØmac*com> //
22
+ // ///
23
+ /////////////////////////////////////////////////////////////////
24
+
25
  /**
26
  * This is a caching extension for getID3(). It works the exact same
27
  * way as the getID3 class, but return cached information much faster
95
  *
96
  *
97
  */
98
+ class getID3_cached_sqlite3 extends getID3
99
+ {
100
+ /**
101
+ * hold the sqlite db
102
+ *
103
+ * @var SQLite3 Resource
104
+ */
105
+ private $db;
106
 
107
  /**
108
+ * table to use for caching
109
+ *
110
+ * @var string $table
111
+ */
112
+ private $table;
113
+
114
+ /**
115
+ * @param string $table holds name of sqlite table
116
+ * @param boolean $hide
117
+ *
118
+ * @throws getid3_exception
119
+ * @throws Exception
120
+ */
121
  public function __construct($table='getid3_cache', $hide=false) {
122
+ // Check for SQLite3 support
123
+ if (!function_exists('sqlite_open')) {
124
+ throw new Exception('PHP not compiled with SQLite3 support.');
125
+ }
126
+
127
  $this->table = $table; // Set table
128
  $file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite';
129
  if ($hide) {
133
  $db = $this->db;
134
  $this->create_table(); // Create cache table if not exists
135
  $version = '';
136
+ $sql = $this->getQuery('version_check');
137
  $stmt = $db->prepare($sql);
138
  $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
139
  $result = $stmt->execute();
141
  if ($version != getID3::VERSION) { // Check version number and clear cache if changed
142
  $this->clear_cache();
143
  }
144
+ parent::__construct();
145
  }
146
 
147
  /**
148
+ * close the database connection
149
+ */
150
  public function __destruct() {
151
  $db=$this->db;
152
  $db->close();
153
  }
154
 
155
  /**
156
+ * clear the cache
157
+ *
158
+ * @return SQLite3Result
159
+ */
 
 
 
 
 
 
 
 
 
 
 
 
160
  private function clear_cache() {
161
  $db = $this->db;
162
+ $sql = $this->getQuery('delete_cache');
163
  $db->exec($sql);
164
+ $sql = $this->getQuery('set_version');
165
  $stmt = $db->prepare($sql);
166
  $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
167
  $stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT);
170
  }
171
 
172
  /**
173
+ * analyze file and cache them, if cached pull from the db
174
+ *
175
+ * @param string $filename
176
+ * @param integer $filesize
177
+ * @param string $original_filename
178
+ *
179
+ * @return mixed|false
180
+ */
181
  public function analyze($filename, $filesize=null, $original_filename='') {
182
  if (!file_exists($filename)) {
183
  return false;
184
  }
185
  // items to track for caching
186
  $filetime = filemtime($filename);
187
+ $filesize_real = filesize($filename);
188
  // this will be saved for a quick directory lookup of analized files
189
  // ... why do 50 seperate sql quries when you can do 1 for the same result
190
  $dirname = dirname($filename);
191
  // Lookup file
192
  $db = $this->db;
193
+ $sql = $this->getQuery('get_id3_data');
194
  $stmt = $db->prepare($sql);
195
+ $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
196
+ $stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
197
+ $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
198
  $res = $stmt->execute();
199
  list($result) = $res->fetchArray();
200
  if (count($result) > 0 ) {
201
  return unserialize(base64_decode($result));
202
  }
203
  // if it hasn't been analyzed before, then do it now
204
+ $analysis = parent::analyze($filename, $filesize, $original_filename);
205
  // Save result
206
+ $sql = $this->getQuery('cache_file');
207
  $stmt = $db->prepare($sql);
208
+ $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
209
+ $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
210
+ $stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
211
+ $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
212
+ $stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
213
+ $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
214
  $res = $stmt->execute();
215
  return $analysis;
216
  }
217
 
218
  /**
219
+ * create data base table
220
+ * this is almost the same as MySQL, with the exception of the dirname being added
221
+ *
222
+ * @return bool
223
+ */
224
  private function create_table() {
225
  $db = $this->db;
226
+ $sql = $this->getQuery('make_table');
227
  return $db->exec($sql);
228
  }
229
 
230
  /**
231
+ * get cached directory
232
+ *
233
+ * This function is not in the MySQL extention, it's ment to speed up requesting multiple files
234
+ * which is ideal for podcasting, playlists, etc.
235
+ *
236
+ * @param string $dir directory to search the cache database for
237
+ *
238
+ * @return array return an array of matching id3 data
239
+ */
240
  public function get_cached_dir($dir) {
241
  $db = $this->db;
242
  $rows = array();
243
+ $sql = $this->getQuery('get_cached_dir');
244
  $stmt = $db->prepare($sql);
245
  $stmt->bindValue(':dirname', $dir, SQLITE3_TEXT);
246
  $res = $stmt->execute();
251
  }
252
 
253
  /**
254
+ * returns NULL if query is not found
255
+ *
256
+ * @param string $name
257
+ *
258
+ * @return null|string
259
+ */
260
+ public function getQuery($name)
261
+ {
262
+ switch ($name) {
263
  case 'version_check':
264
  return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
265
  break;
276
  return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
277
  break;
278
  case 'make_table':
 
279
  return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
280
  break;
281
  case 'get_cached_dir':
282
  return "SELECT val FROM $this->table WHERE dirname = :dirname";
283
  break;
284
+ default:
285
+ return null;
286
  }
287
+ }
288
+
289
+ /**
290
+ * use the magical __get() for sql queries
291
+ *
292
+ * access as easy as $this->{case name}, returns NULL if query is not found
293
+ *
294
+ * @param string $name
295
+ *
296
+ * @return string
297
+ * @deprecated use getQuery() instead
298
+ */
299
+ public function __get($name) {
300
+ return $this->getQuery($name);
301
  }
302
 
303
  }
lib/getid3/getid3.lib.php CHANGED
@@ -1,20 +1,27 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
  // //
9
  // getid3.lib.php - part of getID3() //
10
- // See readme.txt for more details //
11
  // ///
12
  /////////////////////////////////////////////////////////////////
13
 
14
 
15
  class getid3_lib
16
  {
17
-
 
 
 
 
 
 
 
18
  public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
19
  $returnstring = '';
20
  for ($i = 0; $i < strlen($string); $i++) {
@@ -36,9 +43,14 @@ class getid3_lib
36
  return $returnstring;
37
  }
38
 
 
 
 
 
 
 
 
39
  public static function trunc($floatnumber) {
40
- // truncates a floating-point number at the decimal point
41
- // returns int (if possible, otherwise float)
42
  if ($floatnumber >= 1) {
43
  $truncatednumber = floor($floatnumber);
44
  } elseif ($floatnumber <= -1) {
@@ -52,7 +64,12 @@ class getid3_lib
52
  return $truncatednumber;
53
  }
54
 
55
-
 
 
 
 
 
56
  public static function safe_inc(&$variable, $increment=1) {
57
  if (isset($variable)) {
58
  $variable += $increment;
@@ -62,6 +79,11 @@ class getid3_lib
62
  return true;
63
  }
64
 
 
 
 
 
 
65
  public static function CastAsInt($floatnum) {
66
  // convert to float if not already
67
  $floatnum = (float) $floatnum;
@@ -77,6 +99,11 @@ class getid3_lib
77
  return $floatnum;
78
  }
79
 
 
 
 
 
 
80
  public static function intValueSupported($num) {
81
  // check if integers are 64-bit
82
  static $hasINT64 = null;
@@ -93,21 +120,36 @@ class getid3_lib
93
  return false;
94
  }
95
 
 
 
 
 
 
96
  public static function DecimalizeFraction($fraction) {
97
  list($numerator, $denominator) = explode('/', $fraction);
98
  return $numerator / ($denominator ? $denominator : 1);
99
  }
100
 
101
-
 
 
 
 
102
  public static function DecimalBinary2Float($binarynumerator) {
103
  $numerator = self::Bin2Dec($binarynumerator);
104
  $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
105
  return ($numerator / $denominator);
106
  }
107
 
108
-
 
 
 
 
 
 
 
109
  public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
110
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
111
  if (strpos($binarypointnumber, '.') === false) {
112
  $binarypointnumber = '0.'.$binarypointnumber;
113
  } elseif ($binarypointnumber{0} == '.') {
@@ -129,9 +171,14 @@ class getid3_lib
129
  return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
130
  }
131
 
132
-
 
 
 
 
 
 
133
  public static function Float2BinaryDecimal($floatvalue) {
134
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
135
  $maxbits = 128; // to how many bits of precision should the calculations be taken?
136
  $intpart = self::trunc($floatvalue);
137
  $floatpart = abs($floatvalue - $intpart);
@@ -145,9 +192,17 @@ class getid3_lib
145
  return $binarypointnumber;
146
  }
147
 
148
-
 
 
 
 
 
 
 
149
  public static function Float2String($floatvalue, $bits) {
150
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
 
151
  switch ($bits) {
152
  case 32:
153
  $exponentbits = 8;
@@ -176,22 +231,34 @@ class getid3_lib
176
  return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
177
  }
178
 
179
-
 
 
 
 
180
  public static function LittleEndian2Float($byteword) {
181
  return self::BigEndian2Float(strrev($byteword));
182
  }
183
 
184
-
 
 
 
 
 
 
 
 
 
185
  public static function BigEndian2Float($byteword) {
186
- // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
187
- // http://www.psc.edu/general/software/packages/ieee/ieee.html
188
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
189
-
190
  $bitword = self::BigEndian2Bin($byteword);
191
  if (!$bitword) {
192
  return 0;
193
  }
194
  $signbit = $bitword{0};
 
 
 
195
 
196
  switch (strlen($byteword) * 8) {
197
  case 32:
@@ -259,7 +326,14 @@ class getid3_lib
259
  return (float) $floatvalue;
260
  }
261
 
262
-
 
 
 
 
 
 
 
263
  public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
264
  $intvalue = 0;
265
  $bytewordlen = strlen($byteword);
@@ -288,12 +362,30 @@ class getid3_lib
288
  return self::CastAsInt($intvalue);
289
  }
290
 
291
-
 
 
 
 
 
292
  public static function LittleEndian2Int($byteword, $signed=false) {
293
  return self::BigEndian2Int(strrev($byteword), false, $signed);
294
  }
295
 
 
 
 
 
 
 
 
 
296
 
 
 
 
 
 
297
  public static function BigEndian2Bin($byteword) {
298
  $binvalue = '';
299
  $bytewordlen = strlen($byteword);
@@ -303,7 +395,15 @@ class getid3_lib
303
  return $binvalue;
304
  }
305
 
306
-
 
 
 
 
 
 
 
 
307
  public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
308
  if ($number < 0) {
309
  throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
@@ -324,7 +424,11 @@ class getid3_lib
324
  return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
325
  }
326
 
327
-
 
 
 
 
328
  public static function Dec2Bin($number) {
329
  while ($number >= 256) {
330
  $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
@@ -338,7 +442,12 @@ class getid3_lib
338
  return $binstring;
339
  }
340
 
341
-
 
 
 
 
 
342
  public static function Bin2Dec($binstring, $signed=false) {
343
  $signmult = 1;
344
  if ($signed) {
@@ -354,7 +463,11 @@ class getid3_lib
354
  return self::CastAsInt($decvalue * $signmult);
355
  }
356
 
357
-
 
 
 
 
358
  public static function Bin2String($binstring) {
359
  // return 'hi' for input of '0110100001101001'
360
  $string = '';
@@ -365,7 +478,13 @@ class getid3_lib
365
  return $string;
366
  }
367
 
368
-
 
 
 
 
 
 
369
  public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
370
  $intstring = '';
371
  while ($number > 0) {
@@ -380,7 +499,12 @@ class getid3_lib
380
  return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
381
  }
382
 
383
-
 
 
 
 
 
384
  public static function array_merge_clobber($array1, $array2) {
385
  // written by kcØhireability*com
386
  // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
@@ -398,7 +522,12 @@ class getid3_lib
398
  return $newarray;
399
  }
400
 
401
-
 
 
 
 
 
402
  public static function array_merge_noclobber($array1, $array2) {
403
  if (!is_array($array1) || !is_array($array2)) {
404
  return false;
@@ -414,6 +543,12 @@ class getid3_lib
414
  return $newarray;
415
  }
416
 
 
 
 
 
 
 
417
  public static function flipped_array_merge_noclobber($array1, $array2) {
418
  if (!is_array($array1) || !is_array($array2)) {
419
  return false;
@@ -428,7 +563,11 @@ class getid3_lib
428
  return array_flip($newarray);
429
  }
430
 
431
-
 
 
 
 
432
  public static function ksort_recursive(&$theArray) {
433
  ksort($theArray);
434
  foreach ($theArray as $key => $value) {
@@ -439,6 +578,12 @@ class getid3_lib
439
  return true;
440
  }
441
 
 
 
 
 
 
 
442
  public static function fileextension($filename, $numextensions=1) {
443
  if (strstr($filename, '.')) {
444
  $reversedfilename = strrev($filename);
@@ -454,7 +599,11 @@ class getid3_lib
454
  return '';
455
  }
456
 
457
-
 
 
 
 
458
  public static function PlaytimeString($seconds) {
459
  $sign = (($seconds < 0) ? '-' : '');
460
  $seconds = round(abs($seconds));
@@ -464,30 +613,53 @@ class getid3_lib
464
  return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
465
  }
466
 
467
-
 
 
 
 
468
  public static function DateMac2Unix($macdate) {
469
  // Macintosh timestamp: seconds since 00:00h January 1, 1904
470
  // UNIX timestamp: seconds since 00:00h January 1, 1970
471
  return self::CastAsInt($macdate - 2082844800);
472
  }
473
 
474
-
 
 
 
 
475
  public static function FixedPoint8_8($rawdata) {
476
  return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
477
  }
478
 
479
-
 
 
 
 
480
  public static function FixedPoint16_16($rawdata) {
481
  return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
482
  }
483
 
484
-
 
 
 
 
485
  public static function FixedPoint2_30($rawdata) {
486
  $binarystring = self::BigEndian2Bin($rawdata);
487
  return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
488
  }
489
 
490
 
 
 
 
 
 
 
 
491
  public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
492
  // assigns $Value to a nested array path:
493
  // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
@@ -504,6 +676,12 @@ class getid3_lib
504
  return $ReturnedArray;
505
  }
506
 
 
 
 
 
 
 
507
  public static function array_max($arraydata, $returnkey=false) {
508
  $maxvalue = false;
509
  $maxkey = false;
@@ -518,6 +696,12 @@ class getid3_lib
518
  return ($returnkey ? $maxkey : $maxvalue);
519
  }
520
 
 
 
 
 
 
 
521
  public static function array_min($arraydata, $returnkey=false) {
522
  $minvalue = false;
523
  $minkey = false;
@@ -532,6 +716,11 @@ class getid3_lib
532
  return ($returnkey ? $minkey : $minvalue);
533
  }
534
 
 
 
 
 
 
535
  public static function XML2array($XMLstring) {
536
  if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
537
  // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
@@ -545,22 +734,42 @@ class getid3_lib
545
  return false;
546
  }
547
 
 
 
 
 
 
548
  public static function SimpleXMLelement2array($XMLobject) {
549
  if (!is_object($XMLobject) && !is_array($XMLobject)) {
550
  return $XMLobject;
551
  }
552
- $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
553
  foreach ($XMLarray as $key => $value) {
554
  $XMLarray[$key] = self::SimpleXMLelement2array($value);
555
  }
556
  return $XMLarray;
557
  }
558
 
559
-
560
- // Allan Hansen <ahØartemis*dk>
561
- // self::md5_data() - returns md5sum for a file from startuing position to absolute end position
 
 
 
 
 
 
 
 
 
 
 
562
  public static function hash_data($file, $offset, $end, $algorithm) {
563
  static $tempdir = '';
 
 
 
 
564
  if (!self::intValueSupported($end)) {
565
  return false;
566
  }
@@ -645,6 +854,15 @@ class getid3_lib
645
  return $result;
646
  }
647
 
 
 
 
 
 
 
 
 
 
648
  public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
649
  if (!self::intValueSupported($offset + $length)) {
650
  throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
@@ -657,21 +875,25 @@ class getid3_lib
657
  $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
658
  $byteslefttowrite -= $byteswritten;
659
  }
 
660
  return true;
661
  } else {
 
662
  throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
663
  }
664
- fclose($fp_dest);
665
  } else {
666
  throw new Exception('failed to create file for writing '.$filename_dest);
667
  }
668
- fclose($fp_src);
669
  } else {
670
  throw new Exception('failed to open file for reading '.$filename_source);
671
  }
672
- return false;
673
  }
674
 
 
 
 
 
 
675
  public static function iconv_fallback_int_utf8($charval) {
676
  if ($charval < 128) {
677
  // 0bbbbbbb
@@ -695,7 +917,14 @@ class getid3_lib
695
  return $newcharstring;
696
  }
697
 
698
- // ISO-8859-1 => UTF-8
 
 
 
 
 
 
 
699
  public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
700
  if (function_exists('utf8_encode')) {
701
  return utf8_encode($string);
@@ -712,7 +941,14 @@ class getid3_lib
712
  return $newcharstring;
713
  }
714
 
715
- // ISO-8859-1 => UTF-16BE
 
 
 
 
 
 
 
716
  public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
717
  $newcharstring = '';
718
  if ($bom) {
@@ -724,7 +960,14 @@ class getid3_lib
724
  return $newcharstring;
725
  }
726
 
727
- // ISO-8859-1 => UTF-16LE
 
 
 
 
 
 
 
728
  public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
729
  $newcharstring = '';
730
  if ($bom) {
@@ -736,12 +979,24 @@ class getid3_lib
736
  return $newcharstring;
737
  }
738
 
739
- // ISO-8859-1 => UTF-16LE (BOM)
 
 
 
 
 
 
740
  public static function iconv_fallback_iso88591_utf16($string) {
741
  return self::iconv_fallback_iso88591_utf16le($string, true);
742
  }
743
 
744
- // UTF-8 => ISO-8859-1
 
 
 
 
 
 
745
  public static function iconv_fallback_utf8_iso88591($string) {
746
  if (function_exists('utf8_decode')) {
747
  return utf8_decode($string);
@@ -785,7 +1040,14 @@ class getid3_lib
785
  return $newcharstring;
786
  }
787
 
788
- // UTF-8 => UTF-16BE
 
 
 
 
 
 
 
789
  public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
790
  $newcharstring = '';
791
  if ($bom) {
@@ -828,7 +1090,14 @@ class getid3_lib
828
  return $newcharstring;
829
  }
830
 
831
- // UTF-8 => UTF-16LE
 
 
 
 
 
 
 
832
  public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
833
  $newcharstring = '';
834
  if ($bom) {
@@ -871,12 +1140,24 @@ class getid3_lib
871
  return $newcharstring;
872
  }
873
 
874
- // UTF-8 => UTF-16LE (BOM)
 
 
 
 
 
 
875
  public static function iconv_fallback_utf8_utf16($string) {
876
  return self::iconv_fallback_utf8_utf16le($string, true);
877
  }
878
 
879
- // UTF-16BE => UTF-8
 
 
 
 
 
 
880
  public static function iconv_fallback_utf16be_utf8($string) {
881
  if (substr($string, 0, 2) == "\xFE\xFF") {
882
  // strip BOM
@@ -890,7 +1171,13 @@ class getid3_lib
890
  return $newcharstring;
891
  }
892
 
893
- // UTF-16LE => UTF-8
 
 
 
 
 
 
894
  public static function iconv_fallback_utf16le_utf8($string) {
895
  if (substr($string, 0, 2) == "\xFF\xFE") {
896
  // strip BOM
@@ -904,7 +1191,13 @@ class getid3_lib
904
  return $newcharstring;
905
  }
906
 
907
- // UTF-16BE => ISO-8859-1
 
 
 
 
 
 
908
  public static function iconv_fallback_utf16be_iso88591($string) {
909
  if (substr($string, 0, 2) == "\xFE\xFF") {
910
  // strip BOM
@@ -918,7 +1211,13 @@ class getid3_lib
918
  return $newcharstring;
919
  }
920
 
921
- // UTF-16LE => ISO-8859-1
 
 
 
 
 
 
922
  public static function iconv_fallback_utf16le_iso88591($string) {
923
  if (substr($string, 0, 2) == "\xFF\xFE") {
924
  // strip BOM
@@ -932,7 +1231,13 @@ class getid3_lib
932
  return $newcharstring;
933
  }
934
 
935
- // UTF-16 (BOM) => ISO-8859-1
 
 
 
 
 
 
936
  public static function iconv_fallback_utf16_iso88591($string) {
937
  $bom = substr($string, 0, 2);
938
  if ($bom == "\xFE\xFF") {
@@ -943,7 +1248,13 @@ class getid3_lib
943
  return $string;
944
  }
945
 
946
- // UTF-16 (BOM) => UTF-8
 
 
 
 
 
 
947
  public static function iconv_fallback_utf16_utf8($string) {
948
  $bom = substr($string, 0, 2);
949
  if ($bom == "\xFE\xFF") {
@@ -954,14 +1265,34 @@ class getid3_lib
954
  return $string;
955
  }
956
 
 
 
 
 
 
 
 
 
957
  public static function iconv_fallback($in_charset, $out_charset, $string) {
958
 
959
  if ($in_charset == $out_charset) {
960
  return $string;
961
  }
962
 
963
- // iconv() availble
964
- if (function_exists('iconv')) {
 
 
 
 
 
 
 
 
 
 
 
 
965
  if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
966
  switch ($out_charset) {
967
  case 'ISO-8859-1':
@@ -977,7 +1308,7 @@ class getid3_lib
977
  }
978
 
979
 
980
- // iconv() not available
981
  static $ConversionFunctionList = array();
982
  if (empty($ConversionFunctionList)) {
983
  $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8';
@@ -999,9 +1330,15 @@ class getid3_lib
999
  $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
1000
  return self::$ConversionFunction($string);
1001
  }
1002
- throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
1003
  }
1004
 
 
 
 
 
 
 
1005
  public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
1006
  if (is_string($data)) {
1007
  return self::MultiByteCharString2HTML($data, $charset);
@@ -1016,42 +1353,48 @@ class getid3_lib
1016
  return $data;
1017
  }
1018
 
 
 
 
 
 
 
1019
  public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
1020
  $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
1021
  $HTMLstring = '';
1022
 
1023
- switch ($charset) {
1024
  case '1251':
1025
  case '1252':
1026
  case '866':
1027
  case '932':
1028
  case '936':
1029
  case '950':
1030
- case 'BIG5':
1031
- case 'BIG5-HKSCS':
1032
  case 'cp1251':
1033
  case 'cp1252':
1034
  case 'cp866':
1035
- case 'EUC-JP':
1036
- case 'EUCJP':
1037
- case 'GB2312':
1038
  case 'ibm866':
1039
- case 'ISO-8859-1':
1040
- case 'ISO-8859-15':
1041
- case 'ISO8859-1':
1042
- case 'ISO8859-15':
1043
- case 'KOI8-R':
1044
  case 'koi8-ru':
1045
  case 'koi8r':
1046
- case 'Shift_JIS':
1047
- case 'SJIS':
1048
  case 'win-1251':
1049
- case 'Windows-1251':
1050
- case 'Windows-1252':
1051
  $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
1052
  break;
1053
 
1054
- case 'UTF-8':
1055
  $strlen = strlen($string);
1056
  for ($i = 0; $i < $strlen; $i++) {
1057
  $char_ord_val = ord($string{$i});
@@ -1079,7 +1422,7 @@ class getid3_lib
1079
  }
1080
  break;
1081
 
1082
- case 'UTF-16LE':
1083
  for ($i = 0; $i < strlen($string); $i += 2) {
1084
  $charval = self::LittleEndian2Int(substr($string, $i, 2));
1085
  if (($charval >= 32) && ($charval <= 127)) {
@@ -1090,7 +1433,7 @@ class getid3_lib
1090
  }
1091
  break;
1092
 
1093
- case 'UTF-16BE':
1094
  for ($i = 0; $i < strlen($string); $i += 2) {
1095
  $charval = self::BigEndian2Int(substr($string, $i, 2));
1096
  if (($charval >= 32) && ($charval <= 127)) {
@@ -1108,8 +1451,11 @@ class getid3_lib
1108
  return $HTMLstring;
1109
  }
1110
 
1111
-
1112
-
 
 
 
1113
  public static function RGADnameLookup($namecode) {
1114
  static $RGADname = array();
1115
  if (empty($RGADname)) {
@@ -1121,7 +1467,11 @@ class getid3_lib
1121
  return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
1122
  }
1123
 
1124
-
 
 
 
 
1125
  public static function RGADoriginatorLookup($originatorcode) {
1126
  static $RGADoriginator = array();
1127
  if (empty($RGADoriginator)) {
@@ -1134,16 +1484,27 @@ class getid3_lib
1134
  return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
1135
  }
1136
 
1137
-
 
 
 
 
 
1138
  public static function RGADadjustmentLookup($rawadjustment, $signbit) {
1139
- $adjustment = $rawadjustment / 10;
1140
  if ($signbit == 1) {
1141
  $adjustment *= -1;
1142
  }
1143
- return (float) $adjustment;
1144
  }
1145
 
1146
-
 
 
 
 
 
 
1147
  public static function RGADgainString($namecode, $originatorcode, $replaygain) {
1148
  if ($replaygain < 0) {
1149
  $signbit = '1';
@@ -1159,19 +1520,37 @@ class getid3_lib
1159
  return $gainstring;
1160
  }
1161
 
 
 
 
 
 
1162
  public static function RGADamplitude2dB($amplitude) {
1163
  return 20 * log10($amplitude);
1164
  }
1165
 
1166
-
 
 
 
 
 
1167
  public static function GetDataImageSize($imgData, &$imageinfo=array()) {
1168
  static $tempdir = '';
1169
  if (empty($tempdir)) {
 
 
 
 
1170
  // yes this is ugly, feel free to suggest a better way
1171
- require_once(dirname(__FILE__).'/getid3.php');
1172
- $getid3_temp = new getID3();
1173
- $tempdir = $getid3_temp->tempdir;
1174
- unset($getid3_temp);
 
 
 
 
1175
  }
1176
  $GetDataImageSize = false;
1177
  if ($tempfilename = tempnam($tempdir, 'gI3')) {
@@ -1190,32 +1569,21 @@ class getid3_lib
1190
  return $GetDataImageSize;
1191
  }
1192
 
 
 
 
 
 
1193
  public static function ImageExtFromMime($mime_type) {
1194
  // temporary way, works OK for now, but should be reworked in the future
1195
  return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
1196
  }
1197
 
1198
- public static function ImageTypesLookup($imagetypeid) {
1199
- static $ImageTypesLookup = array();
1200
- if (empty($ImageTypesLookup)) {
1201
- $ImageTypesLookup[1] = 'gif';
1202
- $ImageTypesLookup[2] = 'jpeg';
1203
- $ImageTypesLookup[3] = 'png';
1204
- $ImageTypesLookup[4] = 'swf';
1205
- $ImageTypesLookup[5] = 'psd';
1206
- $ImageTypesLookup[6] = 'bmp';
1207
- $ImageTypesLookup[7] = 'tiff (little-endian)';
1208
- $ImageTypesLookup[8] = 'tiff (big-endian)';
1209
- $ImageTypesLookup[9] = 'jpc';
1210
- $ImageTypesLookup[10] = 'jp2';
1211
- $ImageTypesLookup[11] = 'jpx';
1212
- $ImageTypesLookup[12] = 'jb2';
1213
- $ImageTypesLookup[13] = 'swc';
1214
- $ImageTypesLookup[14] = 'iff';
1215
- }
1216
- return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : '');
1217
- }
1218
-
1219
  public static function CopyTagsToComments(&$ThisFileInfo) {
1220
 
1221
  // Copy all entries from ['tags'] into common ['comments']
@@ -1254,10 +1622,14 @@ class getid3_lib
1254
  }
1255
  if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
1256
  $value = (is_string($value) ? trim($value) : $value);
1257
- if (!is_numeric($key)) {
1258
  $ThisFileInfo['comments'][$tagname][$key] = $value;
1259
  } else {
1260
- $ThisFileInfo['comments'][$tagname][] = $value;
 
 
 
 
1261
  }
1262
  }
1263
  }
@@ -1265,6 +1637,18 @@ class getid3_lib
1265
  }
1266
  }
1267
 
 
 
 
 
 
 
 
 
 
 
 
 
1268
  // Copy to ['comments_html']
1269
  if (!empty($ThisFileInfo['comments'])) {
1270
  foreach ($ThisFileInfo['comments'] as $field => $values) {
@@ -1287,7 +1671,15 @@ class getid3_lib
1287
  return true;
1288
  }
1289
 
1290
-
 
 
 
 
 
 
 
 
1291
  public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
1292
 
1293
  // Cached
@@ -1334,6 +1726,14 @@ class getid3_lib
1334
  return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
1335
  }
1336
 
 
 
 
 
 
 
 
 
1337
  public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
1338
  global $GETID3_ERRORARRAY;
1339
 
@@ -1354,10 +1754,20 @@ class getid3_lib
1354
  return false;
1355
  }
1356
 
 
 
 
 
 
1357
  public static function trimNullByte($string) {
1358
  return trim($string, "\x00");
1359
  }
1360
 
 
 
 
 
 
1361
  public static function getFileSizeSyscall($path) {
1362
  $filesize = false;
1363
 
@@ -1382,13 +1792,44 @@ class getid3_lib
1382
  return $filesize;
1383
  }
1384
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1385
 
1386
  /**
1387
- * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
1388
- * @param string $path A path.
1389
- * @param string $suffix If the name component ends in suffix this will also be cut off.
1390
- * @return string
1391
- */
 
 
1392
  public static function mb_basename($path, $suffix = null) {
1393
  $splited = preg_split('#/#', rtrim($path, '/ '));
1394
  return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
 
8
  // //
9
  // getid3.lib.php - part of getID3() //
10
+ // see readme.txt for more details //
11
  // ///
12
  /////////////////////////////////////////////////////////////////
13
 
14
 
15
  class getid3_lib
16
  {
17
+ /**
18
+ * @param string $string
19
+ * @param bool $hex
20
+ * @param bool $spaces
21
+ * @param string $htmlencoding
22
+ *
23
+ * @return string
24
+ */
25
  public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
26
  $returnstring = '';
27
  for ($i = 0; $i < strlen($string); $i++) {
43
  return $returnstring;
44
  }
45
 
46
+ /**
47
+ * Truncates a floating-point number at the decimal point.
48
+ *
49
+ * @param float $floatnumber
50
+ *
51
+ * @return float|int returns int (if possible, otherwise float)
52
+ */
53
  public static function trunc($floatnumber) {
 
 
54
  if ($floatnumber >= 1) {
55
  $truncatednumber = floor($floatnumber);
56
  } elseif ($floatnumber <= -1) {
64
  return $truncatednumber;
65
  }
66
 
67
+ /**
68
+ * @param int|null $variable
69
+ * @param int $increment
70
+ *
71
+ * @return bool
72
+ */
73
  public static function safe_inc(&$variable, $increment=1) {
74
  if (isset($variable)) {
75
  $variable += $increment;
79
  return true;
80
  }
81
 
82
+ /**
83
+ * @param int|float $floatnum
84
+ *
85
+ * @return int|float
86
+ */
87
  public static function CastAsInt($floatnum) {
88
  // convert to float if not already
89
  $floatnum = (float) $floatnum;
99
  return $floatnum;
100
  }
101
 
102
+ /**
103
+ * @param int $num
104
+ *
105
+ * @return bool
106
+ */
107
  public static function intValueSupported($num) {
108
  // check if integers are 64-bit
109
  static $hasINT64 = null;
120
  return false;
121
  }
122
 
123
+ /**
124
+ * @param string $fraction
125
+ *
126
+ * @return float
127
+ */
128
  public static function DecimalizeFraction($fraction) {
129
  list($numerator, $denominator) = explode('/', $fraction);
130
  return $numerator / ($denominator ? $denominator : 1);
131
  }
132
 
133
+ /**
134
+ * @param string $binarynumerator
135
+ *
136
+ * @return float
137
+ */
138
  public static function DecimalBinary2Float($binarynumerator) {
139
  $numerator = self::Bin2Dec($binarynumerator);
140
  $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
141
  return ($numerator / $denominator);
142
  }
143
 
144
+ /**
145
+ * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
146
+ *
147
+ * @param string $binarypointnumber
148
+ * @param int $maxbits
149
+ *
150
+ * @return array
151
+ */
152
  public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
 
153
  if (strpos($binarypointnumber, '.') === false) {
154
  $binarypointnumber = '0.'.$binarypointnumber;
155
  } elseif ($binarypointnumber{0} == '.') {
171
  return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
172
  }
173
 
174
+ /**
175
+ * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
176
+ *
177
+ * @param float $floatvalue
178
+ *
179
+ * @return string
180
+ */
181
  public static function Float2BinaryDecimal($floatvalue) {
 
182
  $maxbits = 128; // to how many bits of precision should the calculations be taken?
183
  $intpart = self::trunc($floatvalue);
184
  $floatpart = abs($floatvalue - $intpart);
192
  return $binarypointnumber;
193
  }
194
 
195
+ /**
196
+ * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
197
+ *
198
+ * @param float $floatvalue
199
+ * @param int $bits
200
+ *
201
+ * @return string|false
202
+ */
203
  public static function Float2String($floatvalue, $bits) {
204
+ $exponentbits = 0;
205
+ $fractionbits = 0;
206
  switch ($bits) {
207
  case 32:
208
  $exponentbits = 8;
231
  return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
232
  }
233
 
234
+ /**
235
+ * @param string $byteword
236
+ *
237
+ * @return float|false
238
+ */
239
  public static function LittleEndian2Float($byteword) {
240
  return self::BigEndian2Float(strrev($byteword));
241
  }
242
 
243
+ /**
244
+ * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
245
+ *
246
+ * @link http://www.psc.edu/general/software/packages/ieee/ieee.html
247
+ * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
248
+ *
249
+ * @param string $byteword
250
+ *
251
+ * @return float|false
252
+ */
253
  public static function BigEndian2Float($byteword) {
 
 
 
 
254
  $bitword = self::BigEndian2Bin($byteword);
255
  if (!$bitword) {
256
  return 0;
257
  }
258
  $signbit = $bitword{0};
259
+ $floatvalue = 0;
260
+ $exponentbits = 0;
261
+ $fractionbits = 0;
262
 
263
  switch (strlen($byteword) * 8) {
264
  case 32:
326
  return (float) $floatvalue;
327
  }
328
 
329
+ /**
330
+ * @param string $byteword
331
+ * @param bool $synchsafe
332
+ * @param bool $signed
333
+ *
334
+ * @return int|float|false
335
+ * @throws Exception
336
+ */
337
  public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
338
  $intvalue = 0;
339
  $bytewordlen = strlen($byteword);
362
  return self::CastAsInt($intvalue);
363
  }
364
 
365
+ /**
366
+ * @param string $byteword
367
+ * @param bool $signed
368
+ *
369
+ * @return int|float|false
370
+ */
371
  public static function LittleEndian2Int($byteword, $signed=false) {
372
  return self::BigEndian2Int(strrev($byteword), false, $signed);
373
  }
374
 
375
+ /**
376
+ * @param string $byteword
377
+ *
378
+ * @return string
379
+ */
380
+ public static function LittleEndian2Bin($byteword) {
381
+ return self::BigEndian2Bin(strrev($byteword));
382
+ }
383
 
384
+ /**
385
+ * @param string $byteword
386
+ *
387
+ * @return string
388
+ */
389
  public static function BigEndian2Bin($byteword) {
390
  $binvalue = '';
391
  $bytewordlen = strlen($byteword);
395
  return $binvalue;
396
  }
397
 
398
+ /**
399
+ * @param int $number
400
+ * @param int $minbytes
401
+ * @param bool $synchsafe
402
+ * @param bool $signed
403
+ *
404
+ * @return string
405
+ * @throws Exception
406
+ */
407
  public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
408
  if ($number < 0) {
409
  throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
424
  return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
425
  }
426
 
427
+ /**
428
+ * @param int $number
429
+ *
430
+ * @return string
431
+ */
432
  public static function Dec2Bin($number) {
433
  while ($number >= 256) {
434
  $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
442
  return $binstring;
443
  }
444
 
445
+ /**
446
+ * @param string $binstring
447
+ * @param bool $signed
448
+ *
449
+ * @return int|float
450
+ */
451
  public static function Bin2Dec($binstring, $signed=false) {
452
  $signmult = 1;
453
  if ($signed) {
463
  return self::CastAsInt($decvalue * $signmult);
464
  }
465
 
466
+ /**
467
+ * @param string $binstring
468
+ *
469
+ * @return string
470
+ */
471
  public static function Bin2String($binstring) {
472
  // return 'hi' for input of '0110100001101001'
473
  $string = '';
478
  return $string;
479
  }
480
 
481
+ /**
482
+ * @param int $number
483
+ * @param int $minbytes
484
+ * @param bool $synchsafe
485
+ *
486
+ * @return string
487
+ */
488
  public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
489
  $intstring = '';
490
  while ($number > 0) {
499
  return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
500
  }
501
 
502
+ /**
503
+ * @param array $array1
504
+ * @param array $array2
505
+ *
506
+ * @return array|false
507
+ */
508
  public static function array_merge_clobber($array1, $array2) {
509
  // written by kcØhireability*com
510
  // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
522
  return $newarray;
523
  }
524
 
525
+ /**
526
+ * @param array $array1
527
+ * @param array $array2
528
+ *
529
+ * @return array|false
530
+ */
531
  public static function array_merge_noclobber($array1, $array2) {
532
  if (!is_array($array1) || !is_array($array2)) {
533
  return false;
543
  return $newarray;
544
  }
545
 
546
+ /**
547
+ * @param array $array1
548
+ * @param array $array2
549
+ *
550
+ * @return array|false|null
551
+ */
552
  public static function flipped_array_merge_noclobber($array1, $array2) {
553
  if (!is_array($array1) || !is_array($array2)) {
554
  return false;
563
  return array_flip($newarray);
564
  }
565
 
566
+ /**
567
+ * @param array $theArray
568
+ *
569
+ * @return bool
570
+ */
571
  public static function ksort_recursive(&$theArray) {
572
  ksort($theArray);
573
  foreach ($theArray as $key => $value) {
578
  return true;
579
  }
580
 
581
+ /**
582
+ * @param string $filename
583
+ * @param int $numextensions
584
+ *
585
+ * @return string
586
+ */
587
  public static function fileextension($filename, $numextensions=1) {
588
  if (strstr($filename, '.')) {
589
  $reversedfilename = strrev($filename);
599
  return '';
600
  }
601
 
602
+ /**
603
+ * @param int $seconds
604
+ *
605
+ * @return string
606
+ */
607
  public static function PlaytimeString($seconds) {
608
  $sign = (($seconds < 0) ? '-' : '');
609
  $seconds = round(abs($seconds));
613
  return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
614
  }
615
 
616
+ /**
617
+ * @param int $macdate
618
+ *
619
+ * @return int|float
620
+ */
621
  public static function DateMac2Unix($macdate) {
622
  // Macintosh timestamp: seconds since 00:00h January 1, 1904
623
  // UNIX timestamp: seconds since 00:00h January 1, 1970
624
  return self::CastAsInt($macdate - 2082844800);
625
  }
626
 
627
+ /**
628
+ * @param string $rawdata
629
+ *
630
+ * @return float
631
+ */
632
  public static function FixedPoint8_8($rawdata) {
633
  return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
634
  }
635
 
636
+ /**
637
+ * @param string $rawdata
638
+ *
639
+ * @return float
640
+ */
641
  public static function FixedPoint16_16($rawdata) {
642
  return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
643
  }
644
 
645
+ /**
646
+ * @param string $rawdata
647
+ *
648
+ * @return float
649
+ */
650
  public static function FixedPoint2_30($rawdata) {
651
  $binarystring = self::BigEndian2Bin($rawdata);
652
  return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
653
  }
654
 
655
 
656
+ /**
657
+ * @param string $ArrayPath
658
+ * @param string $Separator
659
+ * @param mixed $Value
660
+ *
661
+ * @return array
662
+ */
663
  public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
664
  // assigns $Value to a nested array path:
665
  // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
676
  return $ReturnedArray;
677
  }
678
 
679
+ /**
680
+ * @param array $arraydata
681
+ * @param bool $returnkey
682
+ *
683
+ * @return int|false
684
+ */
685
  public static function array_max($arraydata, $returnkey=false) {
686
  $maxvalue = false;
687
  $maxkey = false;
696
  return ($returnkey ? $maxkey : $maxvalue);
697
  }
698
 
699
+ /**
700
+ * @param array $arraydata
701
+ * @param bool $returnkey
702
+ *
703
+ * @return int|false
704
+ */
705
  public static function array_min($arraydata, $returnkey=false) {
706
  $minvalue = false;
707
  $minkey = false;
716
  return ($returnkey ? $minkey : $minvalue);
717
  }
718
 
719
+ /**
720
+ * @param string $XMLstring
721
+ *
722
+ * @return array|false
723
+ */
724
  public static function XML2array($XMLstring) {
725
  if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
726
  // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
734
  return false;
735
  }
736
 
737
+ /**
738
+ * @param SimpleXMLElement|array $XMLobject
739
+ *
740
+ * @return array
741
+ */
742
  public static function SimpleXMLelement2array($XMLobject) {
743
  if (!is_object($XMLobject) && !is_array($XMLobject)) {
744
  return $XMLobject;
745
  }
746
+ $XMLarray = $XMLobject instanceof SimpleXMLElement ? get_object_vars($XMLobject) : $XMLobject;
747
  foreach ($XMLarray as $key => $value) {
748
  $XMLarray[$key] = self::SimpleXMLelement2array($value);
749
  }
750
  return $XMLarray;
751
  }
752
 
753
+ /**
754
+ * self::md5_data() - returns md5sum for a file from startuing position to absolute end position
755
+ *
756
+ * @author Allan Hansen <ahØartemis*dk>
757
+ *
758
+ * @param string $file
759
+ * @param int $offset
760
+ * @param int $end
761
+ * @param string $algorithm
762
+ *
763
+ * @return string|false
764
+ * @throws Exception
765
+ * @throws getid3_exception
766
+ */
767
  public static function hash_data($file, $offset, $end, $algorithm) {
768
  static $tempdir = '';
769
+ $windows_call = null;
770
+ $unix_call = null;
771
+ $hash_length = null;
772
+ $hash_function = null;
773
  if (!self::intValueSupported($end)) {
774
  return false;
775
  }
854
  return $result;
855
  }
856
 
857
+ /**
858
+ * @param string $filename_source
859
+ * @param string $filename_dest
860
+ * @param int $offset
861
+ * @param int $length
862
+ *
863
+ * @return bool
864
+ * @throws Exception
865
+ */
866
  public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
867
  if (!self::intValueSupported($offset + $length)) {
868
  throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
875
  $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
876
  $byteslefttowrite -= $byteswritten;
877
  }
878
+ fclose($fp_dest);
879
  return true;
880
  } else {
881
+ fclose($fp_src);
882
  throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
883
  }
 
884
  } else {
885
  throw new Exception('failed to create file for writing '.$filename_dest);
886
  }
 
887
  } else {
888
  throw new Exception('failed to open file for reading '.$filename_source);
889
  }
 
890
  }
891
 
892
+ /**
893
+ * @param int $charval
894
+ *
895
+ * @return string
896
+ */
897
  public static function iconv_fallback_int_utf8($charval) {
898
  if ($charval < 128) {
899
  // 0bbbbbbb
917
  return $newcharstring;
918
  }
919
 
920
+ /**
921
+ * ISO-8859-1 => UTF-8
922
+ *
923
+ * @param string $string
924
+ * @param bool $bom
925
+ *
926
+ * @return string
927
+ */
928
  public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
929
  if (function_exists('utf8_encode')) {
930
  return utf8_encode($string);
941
  return $newcharstring;
942
  }
943
 
944
+ /**
945
+ * ISO-8859-1 => UTF-16BE
946
+ *
947
+ * @param string $string
948
+ * @param bool $bom
949
+ *
950
+ * @return string
951
+ */
952
  public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
953
  $newcharstring = '';
954
  if ($bom) {
960
  return $newcharstring;
961
  }
962
 
963
+ /**
964
+ * ISO-8859-1 => UTF-16LE
965
+ *
966
+ * @param string $string
967
+ * @param bool $bom
968
+ *
969
+ * @return string
970
+ */
971
  public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
972
  $newcharstring = '';
973
  if ($bom) {
979
  return $newcharstring;
980
  }
981
 
982
+ /**
983
+ * ISO-8859-1 => UTF-16LE (BOM)
984
+ *
985
+ * @param string $string
986
+ *
987
+ * @return string
988
+ */
989
  public static function iconv_fallback_iso88591_utf16($string) {
990
  return self::iconv_fallback_iso88591_utf16le($string, true);
991
  }
992
 
993
+ /**
994
+ * UTF-8 => ISO-8859-1
995
+ *
996
+ * @param string $string
997
+ *
998
+ * @return string
999
+ */
1000
  public static function iconv_fallback_utf8_iso88591($string) {
1001
  if (function_exists('utf8_decode')) {
1002
  return utf8_decode($string);
1040
  return $newcharstring;
1041
  }
1042
 
1043
+ /**
1044
+ * UTF-8 => UTF-16BE
1045
+ *
1046
+ * @param string $string
1047
+ * @param bool $bom
1048
+ *
1049
+ * @return string
1050
+ */
1051
  public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
1052
  $newcharstring = '';
1053
  if ($bom) {
1090
  return $newcharstring;
1091
  }
1092
 
1093
+ /**
1094
+ * UTF-8 => UTF-16LE
1095
+ *
1096
+ * @param string $string
1097
+ * @param bool $bom
1098
+ *
1099
+ * @return string
1100
+ */
1101
  public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
1102
  $newcharstring = '';
1103
  if ($bom) {
1140
  return $newcharstring;
1141
  }
1142
 
1143
+ /**
1144
+ * UTF-8 => UTF-16LE (BOM)
1145
+ *
1146
+ * @param string $string
1147
+ *
1148
+ * @return string
1149
+ */
1150
  public static function iconv_fallback_utf8_utf16($string) {
1151
  return self::iconv_fallback_utf8_utf16le($string, true);
1152
  }
1153
 
1154
+ /**
1155
+ * UTF-16BE => UTF-8
1156
+ *
1157
+ * @param string $string
1158
+ *
1159
+ * @return string
1160
+ */
1161
  public static function iconv_fallback_utf16be_utf8($string) {
1162
  if (substr($string, 0, 2) == "\xFE\xFF") {
1163
  // strip BOM
1171
  return $newcharstring;
1172
  }
1173
 
1174
+ /**
1175
+ * UTF-16LE => UTF-8
1176
+ *
1177
+ * @param string $string
1178
+ *
1179
+ * @return string
1180
+ */
1181
  public static function iconv_fallback_utf16le_utf8($string) {
1182
  if (substr($string, 0, 2) == "\xFF\xFE") {
1183
  // strip BOM
1191
  return $newcharstring;
1192
  }
1193
 
1194
+ /**
1195
+ * UTF-16BE => ISO-8859-1
1196
+ *
1197
+ * @param string $string
1198
+ *
1199
+ * @return string
1200
+ */
1201
  public static function iconv_fallback_utf16be_iso88591($string) {
1202
  if (substr($string, 0, 2) == "\xFE\xFF") {
1203
  // strip BOM
1211
  return $newcharstring;
1212
  }
1213
 
1214
+ /**
1215
+ * UTF-16LE => ISO-8859-1
1216
+ *
1217
+ * @param string $string
1218
+ *
1219
+ * @return string
1220
+ */
1221
  public static function iconv_fallback_utf16le_iso88591($string) {
1222
  if (substr($string, 0, 2) == "\xFF\xFE") {
1223
  // strip BOM
1231
  return $newcharstring;
1232
  }
1233
 
1234
+ /**
1235
+ * UTF-16 (BOM) => ISO-8859-1
1236
+ *
1237
+ * @param string $string
1238
+ *
1239
+ * @return string
1240
+ */
1241
  public static function iconv_fallback_utf16_iso88591($string) {
1242
  $bom = substr($string, 0, 2);
1243
  if ($bom == "\xFE\xFF") {
1248
  return $string;
1249
  }
1250
 
1251
+ /**
1252
+ * UTF-16 (BOM) => UTF-8
1253
+ *
1254
+ * @param string $string
1255
+ *
1256
+ * @return string
1257
+ */
1258
  public static function iconv_fallback_utf16_utf8($string) {
1259
  $bom = substr($string, 0, 2);
1260
  if ($bom == "\xFE\xFF") {
1265
  return $string;
1266
  }
1267
 
1268
+ /**
1269
+ * @param string $in_charset
1270
+ * @param string $out_charset
1271
+ * @param string $string
1272
+ *
1273
+ * @return string
1274
+ * @throws Exception
1275
+ */
1276
  public static function iconv_fallback($in_charset, $out_charset, $string) {
1277
 
1278
  if ($in_charset == $out_charset) {
1279
  return $string;
1280
  }
1281
 
1282
+ // mb_convert_encoding() available
1283
+ if (function_exists('mb_convert_encoding')) {
1284
+ if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) {
1285
+ switch ($out_charset) {
1286
+ case 'ISO-8859-1':
1287
+ $converted_string = rtrim($converted_string, "\x00");
1288
+ break;
1289
+ }
1290
+ return $converted_string;
1291
+ }
1292
+ return $string;
1293
+ }
1294
+ // iconv() available
1295
+ else if (function_exists('iconv')) {
1296
  if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
1297
  switch ($out_charset) {
1298
  case 'ISO-8859-1':
1308
  }
1309
 
1310
 
1311
+ // neither mb_convert_encoding or iconv() is available
1312
  static $ConversionFunctionList = array();
1313
  if (empty($ConversionFunctionList)) {
1314
  $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8';
1330
  $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
1331
  return self::$ConversionFunction($string);
1332
  }
1333
+ throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
1334
  }
1335
 
1336
+ /**
1337
+ * @param mixed $data
1338
+ * @param string $charset
1339
+ *
1340
+ * @return mixed
1341
+ */
1342
  public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
1343
  if (is_string($data)) {
1344
  return self::MultiByteCharString2HTML($data, $charset);
1353
  return $data;
1354
  }
1355
 
1356
+ /**
1357
+ * @param string|int|float $string
1358
+ * @param string $charset
1359
+ *
1360
+ * @return string
1361
+ */
1362
  public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
1363
  $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
1364
  $HTMLstring = '';
1365
 
1366
+ switch (strtolower($charset)) {
1367
  case '1251':
1368
  case '1252':
1369
  case '866':
1370
  case '932':
1371
  case '936':
1372
  case '950':
1373
+ case 'big5':
1374
+ case 'big5-hkscs':
1375
  case 'cp1251':
1376
  case 'cp1252':
1377
  case 'cp866':
1378
+ case 'euc-jp':
1379
+ case 'eucjp':
1380
+ case 'gb2312':
1381
  case 'ibm866':
1382
+ case 'iso-8859-1':
1383
+ case 'iso-8859-15':
1384
+ case 'iso8859-1':
1385
+ case 'iso8859-15':
1386
+ case 'koi8-r':
1387
  case 'koi8-ru':
1388
  case 'koi8r':
1389
+ case 'shift_jis':
1390
+ case 'sjis':
1391
  case 'win-1251':
1392
+ case 'windows-1251':
1393
+ case 'windows-1252':
1394
  $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
1395
  break;
1396
 
1397
+ case 'utf-8':
1398
  $strlen = strlen($string);
1399
  for ($i = 0; $i < $strlen; $i++) {
1400
  $char_ord_val = ord($string{$i});
1422
  }
1423
  break;
1424
 
1425
+ case 'utf-16le':
1426
  for ($i = 0; $i < strlen($string); $i += 2) {
1427
  $charval = self::LittleEndian2Int(substr($string, $i, 2));
1428
  if (($charval >= 32) && ($charval <= 127)) {
1433
  }
1434
  break;
1435
 
1436
+ case 'utf-16be':
1437
  for ($i = 0; $i < strlen($string); $i += 2) {
1438
  $charval = self::BigEndian2Int(substr($string, $i, 2));
1439
  if (($charval >= 32) && ($charval <= 127)) {
1451
  return $HTMLstring;
1452
  }
1453
 
1454
+ /**
1455
+ * @param int $namecode
1456
+ *
1457
+ * @return string
1458
+ */
1459
  public static function RGADnameLookup($namecode) {
1460
  static $RGADname = array();
1461
  if (empty($RGADname)) {
1467
  return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
1468
  }
1469
 
1470
+ /**
1471
+ * @param int $originatorcode
1472
+ *
1473
+ * @return string
1474
+ */
1475
  public static function RGADoriginatorLookup($originatorcode) {
1476
  static $RGADoriginator = array();
1477
  if (empty($RGADoriginator)) {
1484
  return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
1485
  }
1486
 
1487
+ /**
1488
+ * @param int $rawadjustment
1489
+ * @param int $signbit
1490
+ *
1491
+ * @return float
1492
+ */
1493
  public static function RGADadjustmentLookup($rawadjustment, $signbit) {
1494
+ $adjustment = (float) $rawadjustment / 10;
1495
  if ($signbit == 1) {
1496
  $adjustment *= -1;
1497
  }
1498
+ return $adjustment;
1499
  }
1500
 
1501
+ /**
1502
+ * @param int $namecode
1503
+ * @param int $originatorcode
1504
+ * @param int $replaygain
1505
+ *
1506
+ * @return string
1507
+ */
1508
  public static function RGADgainString($namecode, $originatorcode, $replaygain) {
1509
  if ($replaygain < 0) {
1510
  $signbit = '1';
1520
  return $gainstring;
1521
  }
1522
 
1523
+ /**
1524
+ * @param float $amplitude
1525
+ *
1526
+ * @return float
1527
+ */
1528
  public static function RGADamplitude2dB($amplitude) {
1529
  return 20 * log10($amplitude);
1530
  }
1531
 
1532
+ /**
1533
+ * @param string $imgData
1534
+ * @param array $imageinfo
1535
+ *
1536
+ * @return array|false
1537
+ */
1538
  public static function GetDataImageSize($imgData, &$imageinfo=array()) {
1539
  static $tempdir = '';
1540
  if (empty($tempdir)) {
1541
+ if (function_exists('sys_get_temp_dir')) {
1542
+ $tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52
1543
+ }
1544
+
1545
  // yes this is ugly, feel free to suggest a better way
1546
+ if (include_once(dirname(__FILE__).'/getid3.php')) {
1547
+ if ($getid3_temp = new getID3()) {
1548
+ if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
1549
+ $tempdir = $getid3_temp_tempdir;
1550
+ }
1551
+ unset($getid3_temp, $getid3_temp_tempdir);
1552
+ }
1553
+ }
1554
  }
1555
  $GetDataImageSize = false;
1556
  if ($tempfilename = tempnam($tempdir, 'gI3')) {
1569
  return $GetDataImageSize;
1570
  }
1571
 
1572
+ /**
1573
+ * @param string $mime_type
1574
+ *
1575
+ * @return string
1576
+ */
1577
  public static function ImageExtFromMime($mime_type) {
1578
  // temporary way, works OK for now, but should be reworked in the future
1579
  return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
1580
  }
1581
 
1582
+ /**
1583
+ * @param array $ThisFileInfo
1584
+ *
1585
+ * @return bool
1586
+ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1587
  public static function CopyTagsToComments(&$ThisFileInfo) {
1588
 
1589
  // Copy all entries from ['tags'] into common ['comments']
1622
  }
1623
  if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
1624
  $value = (is_string($value) ? trim($value) : $value);
1625
+ if (!is_int($key) && !ctype_digit($key)) {
1626
  $ThisFileInfo['comments'][$tagname][$key] = $value;
1627
  } else {
1628
+ if (isset($ThisFileInfo['comments'][$tagname])) {
1629
+ $ThisFileInfo['comments'][$tagname] = array($value);
1630
+ } else {
1631
+ $ThisFileInfo['comments'][$tagname][] = $value;
1632
+ }
1633
  }
1634
  }
1635
  }
1637
  }
1638
  }
1639
 
1640
+ // attempt to standardize spelling of returned keys
1641
+ $StandardizeFieldNames = array(
1642
+ 'tracknumber' => 'track_number',
1643
+ 'track' => 'track_number',
1644
+ );
1645
+ foreach ($StandardizeFieldNames as $badkey => $goodkey) {
1646
+ if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) {
1647
+ $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
1648
+ unset($ThisFileInfo['comments'][$badkey]);
1649
+ }
1650
+ }
1651
+
1652
  // Copy to ['comments_html']
1653
  if (!empty($ThisFileInfo['comments'])) {
1654
  foreach ($ThisFileInfo['comments'] as $field => $values) {
1671
  return true;
1672
  }
1673
 
1674
+ /**
1675
+ * @param string $key
1676
+ * @param int $begin
1677
+ * @param int $end
1678
+ * @param string $file
1679
+ * @param string $name
1680
+ *
1681
+ * @return string
1682
+ */
1683
  public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
1684
 
1685
  // Cached
1726
  return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
1727
  }
1728
 
1729
+ /**
1730
+ * @param string $filename
1731
+ * @param string $sourcefile
1732
+ * @param bool $DieOnFailure
1733
+ *
1734
+ * @return bool
1735
+ * @throws Exception
1736
+ */
1737
  public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
1738
  global $GETID3_ERRORARRAY;
1739
 
1754
  return false;
1755
  }
1756
 
1757
+ /**
1758
+ * @param string $string
1759
+ *
1760
+ * @return string
1761
+ */
1762
  public static function trimNullByte($string) {
1763
  return trim($string, "\x00");
1764
  }
1765
 
1766
+ /**
1767
+ * @param string $path
1768
+ *
1769
+ * @return float|bool
1770
+ */
1771
  public static function getFileSizeSyscall($path) {
1772
  $filesize = false;
1773
 
1792
  return $filesize;
1793
  }
1794
 
1795
+ /**
1796
+ * @param string $filename
1797
+ *
1798
+ * @return string|false
1799
+ */
1800
+ public static function truepath($filename) {
1801
+ // 2017-11-08: this could use some improvement, patches welcome
1802
+ if (preg_match('#^(\\\\\\\\|//)[a-z0-9]#i', $filename, $matches)) {
1803
+ // PHP's built-in realpath function does not work on UNC Windows shares
1804
+ $goodpath = array();
1805
+ foreach (explode('/', str_replace('\\', '/', $filename)) as $part) {
1806
+ if ($part == '.') {
1807
+ continue;
1808
+ }
1809
+ if ($part == '..') {
1810
+ if (count($goodpath)) {
1811
+ array_pop($goodpath);
1812
+ } else {
1813
+ // cannot step above this level, already at top level
1814
+ return false;
1815
+ }
1816
+ } else {
1817
+ $goodpath[] = $part;
1818
+ }
1819
+ }
1820
+ return implode(DIRECTORY_SEPARATOR, $goodpath);
1821
+ }
1822
+ return realpath($filename);
1823
+ }
1824
 
1825
  /**
1826
+ * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
1827
+ *
1828
+ * @param string $path A path.
1829
+ * @param string $suffix If the name component ends in suffix this will also be cut off.
1830
+ *
1831
+ * @return string
1832
+ */
1833
  public static function mb_basename($path, $suffix = null) {
1834
  $splited = preg_split('#/#', rtrim($path, '/ '));
1835
  return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
lib/getid3/getid3.php CHANGED
@@ -1,10 +1,9 @@
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
  // //
9
  // Please see readme.txt for more information //
10
  // ///
@@ -22,6 +21,17 @@ if (!defined('GETID3_INCLUDEPATH')) {
22
  if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
23
  define('IMG_JPG', IMAGETYPE_JPEG);
24
  }
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  // attempt to define temp dir as something flexible but reliable
27
  $temp_dir = ini_get('upload_tmp_dir');
@@ -68,253 +78,410 @@ unset($open_basedir, $temp_dir);
68
 
69
  // End: Defines
70
 
71
- // Do not proceed getID3 if already exist.
72
- if ( class_exists ( "getID3" ) ) {
73
- return;
74
- }
75
-
76
- if ( class_exists ( "getid3_exception" ) ) {
77
- return;
78
- }
79
 
80
- if( ! class_exists( 'getID3' ) ){
81
-
82
- class getID3
83
- {
84
- // public: Settings
85
- public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
86
- public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
87
-
88
- // public: Optional tag checks - disable for speed.
89
- public $option_tag_id3v1 = true; // Read and process ID3v1 tags
90
- public $option_tag_id3v2 = true; // Read and process ID3v2 tags
91
- public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
92
- public $option_tag_apetag = true; // Read and process APE tags
93
- public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
94
- public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
95
-
96
- // public: Optional tag/comment calucations
97
- public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
98
-
99
- // public: Optional handling of embedded attachments (e.g. images)
100
- public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
101
-
102
- // public: Optional calculations
103
- public $option_md5_data = false; // Get MD5 sum of data part - slow
104
- public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
105
- public $option_sha1_data = false; // Get SHA1 sum of data part - slow
106
- public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
107
-
108
- // public: Read buffer size in bytes
109
- public $option_fread_buffer_size = 32768;
110
-
111
- // Public variables
112
- public $filename; // Filename of file being analysed.
113
- public $fp; // Filepointer to file being analysed.
114
- public $info; // Result array.
115
- public $tempdir = GETID3_TEMP_DIR;
116
- public $memory_limit = 0;
117
-
118
- // Protected variables
119
- protected $startup_error = '';
120
- protected $startup_warning = '';
121
-
122
- const VERSION = '1.9.10-20150914';
123
- const FREAD_BUFFER_SIZE = 32768;
124
-
125
- const ATTACHMENTS_NONE = false;
126
- const ATTACHMENTS_INLINE = true;
127
-
128
- // public: constructor
129
- public function __construct() {
130
-
131
- // Check for PHP version
132
- $required_php_version = '5.3.0';
133
- if (version_compare(PHP_VERSION, $required_php_version, '<')) {
134
- $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION;
135
- return false;
136
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
- // Check memory
139
- $this->memory_limit = ini_get('memory_limit');
140
- if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
141
- // could be stored as "16M" rather than 16777216 for example
142
- $this->memory_limit = $matches[1] * 1048576;
143
- } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
144
- // could be stored as "2G" rather than 2147483648 for example
145
- $this->memory_limit = $matches[1] * 1073741824;
146
- }
147
- if ($this->memory_limit <= 0) {
148
- // memory limits probably disabled
149
- } elseif ($this->memory_limit <= 4194304) {
150
- $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
151
- } elseif ($this->memory_limit <= 12582912) {
152
- $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
153
- }
154
 
155
- // Check safe_mode off
156
- if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
157
- $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
158
- }
159
 
160
- if (intval(ini_get('mbstring.func_overload')) > 0) {
161
- $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
162
- }
 
 
 
163
 
164
- // Check for magic_quotes_runtime
165
- if (function_exists('get_magic_quotes_runtime')) {
166
- if (get_magic_quotes_runtime()) {
167
- return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
168
- }
169
  }
 
170
 
171
- // Check for magic_quotes_gpc
172
- if (function_exists('magic_quotes_gpc')) {
173
- if (get_magic_quotes_gpc()) {
174
- return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
175
- }
176
  }
 
177
 
178
- // Load support library
179
- if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
180
- $this->startup_error .= 'getid3.lib.php is missing or corrupt';
181
- }
182
 
183
- if ($this->option_max_2gb_check === null) {
184
- $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
185
- }
186
 
187
 
188
- // Needed for Windows only:
189
- // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
190
- // as well as other helper functions such as head, tail, md5sum, etc
191
- // This path cannot contain spaces, but the below code will attempt to get the
192
- // 8.3-equivalent path automatically
193
- // IMPORTANT: This path must include the trailing slash
194
- if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
195
-
196
- $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
197
-
198
- if (!is_dir($helperappsdir)) {
199
- $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
200
- } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
201
- $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
202
- $path_so_far = array();
203
- foreach ($DirPieces as $key => $value) {
204
- if (strpos($value, ' ') !== false) {
205
- if (!empty($path_so_far)) {
206
- $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
207
- $dir_listing = `$commandline`;
208
- $lines = explode("\n", $dir_listing);
209
- foreach ($lines as $line) {
210
- $line = trim($line);
211
- if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
212
- list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
213
- if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
214
- $value = $shortname;
215
- }
216
  }
217
  }
218
- } else {
219
- $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
220
  }
 
 
221
  }
222
- $path_so_far[] = $value;
223
  }
224
- $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
225
  }
226
- define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
227
  }
228
-
229
- return true;
230
  }
231
 
232
- public function version() {
233
- return self::VERSION;
 
234
  }
 
235
 
236
- public function fread_buffer_size() {
237
- return $this->option_fread_buffer_size;
238
- }
 
 
 
239
 
 
 
 
 
 
 
240
 
241
- // public: setOption
242
- public function setOption($optArray) {
243
- if (!is_array($optArray) || empty($optArray)) {
244
- return false;
245
- }
246
- foreach ($optArray as $opt => $val) {
247
- if (isset($this->$opt) === false) {
248
- continue;
249
- }
250
- $this->$opt = $val;
 
 
251
  }
252
- return true;
253
  }
 
 
254
 
255
-
256
- public function openfile($filename, $filesize=null) {
257
- try {
258
- if (!empty($this->startup_error)) {
259
- throw new getid3_exception($this->startup_error);
260
- }
261
- if (!empty($this->startup_warning)) {
262
- $this->warning($this->startup_warning);
 
 
 
 
 
 
 
 
263
  }
 
264
 
265
- // init result array and set parameters
266
- $this->filename = $filename;
267
- $this->info = array();
268
- $this->info['GETID3_VERSION'] = $this->version();
269
- $this->info['php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit : false);
270
 
271
- // remote files not supported
272
- if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
273
- throw new getid3_exception('Remote files are not supported - please copy the file locally first');
274
- }
275
 
276
- $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
277
- $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
278
 
279
- // open local file
280
- //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
281
- if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
282
- // great
283
- } else {
284
- $errormessagelist = array();
285
- if (!is_readable($filename)) {
286
- $errormessagelist[] = '!is_readable';
287
- }
288
- if (!is_file($filename)) {
289
- $errormessagelist[] = '!is_file';
290
- }
291
- if (!file_exists($filename)) {
292
- $errormessagelist[] = '!file_exists';
293
- }
294
- if (empty($errormessagelist)) {
295
- $errormessagelist[] = 'fopen failed';
296
- }
297
- throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
298
  }
 
 
299
 
300
- $this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename));
301
- // set redundant parameters - might be needed in some include file
302
- // filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
303
- $filename = str_replace('\\', '/', $filename);
304
- $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
305
- $this->info['filename'] = getid3_lib::mb_basename($filename);
306
- $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
307
-
308
-
309
- // option_max_2gb_check
310
- if ($this->option_max_2gb_check) {
311
- // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
312
- // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
313
- // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
314
- $fseek = fseek($this->fp, 0, SEEK_END);
315
- if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
316
- ($this->info['filesize'] < 0) ||
317
- (ftell($this->fp) < 0)) {
 
 
 
 
 
 
 
 
 
 
 
318
  $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']);
319
 
320
  if ($real_filesize === false) {
@@ -324,381 +491,402 @@ if( ! class_exists( 'getID3' ) ){
324
  } elseif (getid3_lib::intValueSupported($real_filesize)) {
325
  unset($this->info['filesize']);
326
  fclose($this->fp);
327
- throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
328
  }
329
  $this->info['filesize'] = $real_filesize;
330
- $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
331
- }
332
  }
333
-
334
- // set more parameters
335
- $this->info['avdataoffset'] = 0;
336
- $this->info['avdataend'] = $this->info['filesize'];
337
- $this->info['fileformat'] = ''; // filled in later
338
- $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used
339
- $this->info['video']['dataformat'] = ''; // filled in later, unset if not used
340
- $this->info['tags'] = array(); // filled in later, unset if not used
341
- $this->info['error'] = array(); // filled in later, unset if not used
342
- $this->info['warning'] = array(); // filled in later, unset if not used
343
- $this->info['comments'] = array(); // filled in later, unset if not used
344
- $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired
345
-
346
- return true;
347
-
348
- } catch (Exception $e) {
349
- $this->error($e->getMessage());
350
  }
351
- return false;
 
 
 
 
352
  }
 
 
353
 
354
- // public: analyze file
355
- public function analyze($filename, $filesize=null, $original_filename='') {
356
- try {
357
- if (!$this->openfile($filename, $filesize)) {
358
- return $this->info;
359
- }
 
 
 
 
 
 
 
 
360
 
361
- // Handle tags
362
- foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
363
- $option_tag = 'option_tag_'.$tag_name;
364
- if ($this->$option_tag) {
365
- $this->include_module('tag.'.$tag_name);
366
- try {
367
- $tag_class = 'getid3_'.$tag_name;
368
- $tag = new $tag_class($this);
369
- $tag->Analyze();
370
- }
371
- catch (getid3_exception $e) {
372
- throw $e;
373
- }
374
  }
375
- }
376
- if (isset($this->info['id3v2']['tag_offset_start'])) {
377
- $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']);
378
- }
379
- foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
380
- if (isset($this->info[$tag_key]['tag_offset_start'])) {
381
- $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']);
382
  }
383
  }
384
-
385
- // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
386
- if (!$this->option_tag_id3v2) {
387
- fseek($this->fp, 0);
388
- $header = fread($this->fp, 10);
389
- if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
390
- $this->info['id3v2']['header'] = true;
391
- $this->info['id3v2']['majorversion'] = ord($header{3});
392
- $this->info['id3v2']['minorversion'] = ord($header{4});
393
- $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
394
- }
395
  }
 
396
 
397
- // read 32 kb file data
398
- fseek($this->fp, $this->info['avdataoffset']);
399
- $formattest = fread($this->fp, 32774);
400
-
401
- // determine format
402
- $determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename));
403
-
404
- // unable to determine file format
405
- if (!$determined_format) {
406
- fclose($this->fp);
407
- return $this->error('unable to determine file format');
408
  }
 
409
 
410
- // check for illegal ID3 tags
411
- if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
412
- if ($determined_format['fail_id3'] === 'ERROR') {
413
- fclose($this->fp);
414
- return $this->error('ID3 tags not allowed on this file type.');
415
- } elseif ($determined_format['fail_id3'] === 'WARNING') {
416
- $this->warning('ID3 tags not allowed on this file type.');
417
- }
418
- }
419
 
420
- // check for illegal APE tags
421
- if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
422
- if ($determined_format['fail_ape'] === 'ERROR') {
423
- fclose($this->fp);
424
- return $this->error('APE tags not allowed on this file type.');
425
- } elseif ($determined_format['fail_ape'] === 'WARNING') {
426
- $this->warning('APE tags not allowed on this file type.');
427
- }
428
- }
429
 
430
- // set mime type
431
- $this->info['mime_type'] = $determined_format['mime_type'];
 
 
 
432
 
433
- // supported format signature pattern detected, but module deleted
434
- if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
 
435
  fclose($this->fp);
436
- return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
 
 
437
  }
 
438
 
439
- // module requires iconv support
440
- // Check encoding/iconv support
441
- if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
442
- $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
443
- if (GETID3_OS_ISWINDOWS) {
444
- $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
445
- } else {
446
- $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
447
- }
448
- return $this->error($errormessage);
449
  }
 
450
 
451
- // include module
452
- include_once(GETID3_INCLUDEPATH.$determined_format['include']);
453
-
454
- // instantiate module class
455
- $class_name = 'getid3_'.$determined_format['module'];
456
- if (!class_exists($class_name)) {
457
- return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
458
- }
459
- $class = new $class_name($this);
460
- $class->Analyze();
461
- unset($class);
462
 
463
- // close file
 
464
  fclose($this->fp);
 
 
465
 
466
- // process all tags - copy to 'tags' and convert charsets
467
- if ($this->option_tags_process) {
468
- $this->HandleAllTags();
 
 
 
 
 
469
  }
 
 
470
 
471
- // perform more calculations
472
- if ($this->option_extra_info) {
473
- $this->ChannelsBitratePlaytimeCalculations();
474
- $this->CalculateCompressionRatioVideo();
475
- $this->CalculateCompressionRatioAudio();
476
- $this->CalculateReplayGain();
477
- $this->ProcessAudioStreams();
478
- }
479
 
480
- // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
481
- if ($this->option_md5_data) {
482
- // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
483
- if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
484
- $this->getHashdata('md5');
485
- }
486
- }
 
487
 
488
- // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
489
- if ($this->option_sha1_data) {
490
- $this->getHashdata('sha1');
491
- }
492
 
493
- // remove undesired keys
494
- $this->CleanUp();
 
 
495
 
496
- } catch (Exception $e) {
497
- $this->error('Caught exception: '.$e->getMessage());
 
 
 
 
 
498
  }
499
 
500
- // return info array
501
- return $this->info;
502
- }
 
 
 
 
503
 
 
 
 
 
504
 
505
- // private: error handling
506
- public function error($message) {
507
  $this->CleanUp();
508
- if (!isset($this->info['error'])) {
509
- $this->info['error'] = array();
510
- }
511
- $this->info['error'][] = $message;
512
- return $this->info;
513
  }
514
 
 
 
 
515
 
516
- // private: warning handling
517
- public function warning($message) {
518
- $this->info['warning'][] = $message;
519
- return true;
 
 
 
 
 
 
 
 
520
  }
 
 
 
521
 
522
 
523
- // private: CleanUp
524
- private function CleanUp() {
 
 
 
 
 
 
 
 
 
525
 
526
- // remove possible empty keys
527
- $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
528
- foreach ($AVpossibleEmptyKeys as $dummy => $key) {
529
- if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
530
- unset($this->info['audio'][$key]);
531
- }
532
- if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) {
533
- unset($this->info['video'][$key]);
534
- }
535
- }
536
 
537
- // remove empty root keys
538
- if (!empty($this->info)) {
539
- foreach ($this->info as $key => $value) {
540
- if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) {
541
- unset($this->info[$key]);
542
- }
543
- }
 
 
 
 
 
 
544
  }
 
545
 
546
- // remove meaningless entries from unknown-format files
547
- if (empty($this->info['fileformat'])) {
548
- if (isset($this->info['avdataoffset'])) {
549
- unset($this->info['avdataoffset']);
550
- }
551
- if (isset($this->info['avdataend'])) {
552
- unset($this->info['avdataend']);
553
  }
554
  }
 
555
 
556
- // remove possible duplicated identical entries
557
- if (!empty($this->info['error'])) {
558
- $this->info['error'] = array_values(array_unique($this->info['error']));
 
559
  }
560
- if (!empty($this->info['warning'])) {
561
- $this->info['warning'] = array_values(array_unique($this->info['warning']));
562
  }
 
563
 
564
- // remove "global variable" type keys
565
- unset($this->info['php_memory_limit']);
566
-
567
- return true;
568
  }
 
 
 
 
 
 
569
 
 
 
570
 
571
- // return array containing information about all supported formats
572
- public function GetFileFormatArray() {
573
- static $format_info = array();
574
- if (empty($format_info)) {
575
- $format_info = array(
576
-
577
- // Audio formats
578
-
579
- // AC-3 - audio - Dolby AC-3 / Dolby Digital
580
- 'ac3' => array(
581
- 'pattern' => '^\x0B\x77',
582
- 'group' => 'audio',
583
- 'module' => 'ac3',
584
- 'mime_type' => 'audio/ac3',
585
- ),
586
-
587
- // AAC - audio - Advanced Audio Coding (AAC) - ADIF format
588
- 'adif' => array(
589
- 'pattern' => '^ADIF',
590
- 'group' => 'audio',
591
- 'module' => 'aac',
592
- 'mime_type' => 'application/octet-stream',
593
- 'fail_ape' => 'WARNING',
594
- ),
595
-
596
- /*
597
- // AA - audio - Audible Audiobook
598
- 'aa' => array(
599
- 'pattern' => '^.{4}\x57\x90\x75\x36',
600
- 'group' => 'audio',
601
- 'module' => 'aa',
602
- 'mime_type' => 'audio/audible',
603
- ),
604
- */
605
- // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
606
- 'adts' => array(
607
- 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]',
608
- 'group' => 'audio',
609
- 'module' => 'aac',
610
- 'mime_type' => 'application/octet-stream',
611
- 'fail_ape' => 'WARNING',
612
- ),
613
-
614
-
615
- // AU - audio - NeXT/Sun AUdio (AU)
616
- 'au' => array(
617
- 'pattern' => '^\.snd',
618
- 'group' => 'audio',
619
- 'module' => 'au',
620
- 'mime_type' => 'audio/basic',
621
- ),
622
-
623
- // AMR - audio - Adaptive Multi Rate
624
- 'amr' => array(
625
- 'pattern' => '^\x23\x21AMR\x0A', // #!AMR[0A]
626
- 'group' => 'audio',
627
- 'module' => 'amr',
628
- 'mime_type' => 'audio/amr',
629
- ),
630
-
631
- // AVR - audio - Audio Visual Research
632
- 'avr' => array(
633
- 'pattern' => '^2BIT',
634
- 'group' => 'audio',
635
- 'module' => 'avr',
636
- 'mime_type' => 'application/octet-stream',
637
- ),
638
-
639
- // BONK - audio - Bonk v0.9+
640
- 'bonk' => array(
641
- 'pattern' => '^\x00(BONK|INFO|META| ID3)',
642
- 'group' => 'audio',
643
- 'module' => 'bonk',
644
- 'mime_type' => 'audio/xmms-bonk',
645
- ),
646
-
647
- // DSS - audio - Digital Speech Standard
648
- 'dss' => array(
649
- 'pattern' => '^[\x02-\x03]ds[s2]',
650
- 'group' => 'audio',
651
- 'module' => 'dss',
652
- 'mime_type' => 'application/octet-stream',
653
- ),
654
-
655
- // DTS - audio - Dolby Theatre System
656
- 'dts' => array(
657
- 'pattern' => '^\x7F\xFE\x80\x01',
658
- 'group' => 'audio',
659
- 'module' => 'dts',
660
- 'mime_type' => 'audio/dts',
661
- ),
662
-
663
- // FLAC - audio - Free Lossless Audio Codec
664
- 'flac' => array(
665
- 'pattern' => '^fLaC',
666
- 'group' => 'audio',
667
- 'module' => 'flac',
668
- 'mime_type' => 'audio/x-flac',
669
- ),
670
-
671
- // LA - audio - Lossless Audio (LA)
672
- 'la' => array(
673
- 'pattern' => '^LA0[2-4]',
674
- 'group' => 'audio',
675
- 'module' => 'la',
676
- 'mime_type' => 'application/octet-stream',
677
- ),
678
-
679
- // LPAC - audio - Lossless Predictive Audio Compression (LPAC)
680
- 'lpac' => array(
681
- 'pattern' => '^LPAC',
682
- 'group' => 'audio',
683
- 'module' => 'lpac',
684
- 'mime_type' => 'application/octet-stream',
685
- ),
686
-
687
- // MIDI - audio - MIDI (Musical Instrument Digital Interface)
688
- 'midi' => array(
689
- 'pattern' => '^MThd',
690
- 'group' => 'audio',
691
- 'module' => 'midi',
692
- 'mime_type' => 'audio/midi',
693
- ),
694
-
695
- // MAC - audio - Monkey's Audio Compressor
696
- 'mac' => array(
697
- 'pattern' => '^MAC ',
698
- 'group' => 'audio',
699
- 'module' => 'monkey',
700
- 'mime_type' => 'application/octet-stream',
701
- ),
 
 
 
 
 
 
 
 
 
 
 
 
702
 
703
  // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
704
  // // MOD - audio - MODule (assorted sub-formats)
@@ -710,1132 +898,1280 @@ if( ! class_exists( 'getID3' ) ){
710
  // 'mime_type' => 'audio/mod',
711
  // ),
712
 
713
- // MOD - audio - MODule (Impulse Tracker)
714
- 'it' => array(
715
- 'pattern' => '^IMPM',
716
- 'group' => 'audio',
717
- 'module' => 'mod',
718
- //'option' => 'it',
719
- 'mime_type' => 'audio/it',
720
- ),
721
-
722
- // MOD - audio - MODule (eXtended Module, various sub-formats)
723
- 'xm' => array(
724
- 'pattern' => '^Extended Module',
725
- 'group' => 'audio',
726
- 'module' => 'mod',
727
- //'option' => 'xm',
728
- 'mime_type' => 'audio/xm',
729
- ),
730
-
731
- // MOD - audio - MODule (ScreamTracker)
732
- 's3m' => array(
733
- 'pattern' => '^.{44}SCRM',
734
- 'group' => 'audio',
735
- 'module' => 'mod',
736
- //'option' => 's3m',
737
- 'mime_type' => 'audio/s3m',
738
- ),
739
-
740
- // MPC - audio - Musepack / MPEGplus
741
- 'mpc' => array(
742
- 'pattern' => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
743
- 'group' => 'audio',
744
- 'module' => 'mpc',
745
- 'mime_type' => 'audio/x-musepack',
746
- ),
747
-
748
- // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
749
- 'mp3' => array(
750
- 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
751
- 'group' => 'audio',
752
- 'module' => 'mp3',
753
- 'mime_type' => 'audio/mpeg',
754
- ),
755
-
756
- // OFR - audio - OptimFROG
757
- 'ofr' => array(
758
- 'pattern' => '^(\*RIFF|OFR)',
759
- 'group' => 'audio',
760
- 'module' => 'optimfrog',
761
- 'mime_type' => 'application/octet-stream',
762
- ),
763
-
764
- // RKAU - audio - RKive AUdio compressor
765
- 'rkau' => array(
766
- 'pattern' => '^RKA',
767
- 'group' => 'audio',
768
- 'module' => 'rkau',
769
- 'mime_type' => 'application/octet-stream',
770
- ),
771
-
772
- // SHN - audio - Shorten
773
- 'shn' => array(
774
- 'pattern' => '^ajkg',
775
- 'group' => 'audio',
776
- 'module' => 'shorten',
777
- 'mime_type' => 'audio/xmms-shn',
778
- 'fail_id3' => 'ERROR',
779
- 'fail_ape' => 'ERROR',
780
- ),
781
-
782
- // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
783
- 'tta' => array(
784
- 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)'
785
- 'group' => 'audio',
786
- 'module' => 'tta',
787
- 'mime_type' => 'application/octet-stream',
788
- ),
789
-
790
- // VOC - audio - Creative Voice (VOC)
791
- 'voc' => array(
792
- 'pattern' => '^Creative Voice File',
793
- 'group' => 'audio',
794
- 'module' => 'voc',
795
- 'mime_type' => 'audio/voc',
796
- ),
797
-
798
- // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
799
- 'vqf' => array(
800
- 'pattern' => '^TWIN',
801
- 'group' => 'audio',
802
- 'module' => 'vqf',
803
- 'mime_type' => 'application/octet-stream',
804
- ),
805
-
806
- // WV - audio - WavPack (v4.0+)
807
- 'wv' => array(
808
- 'pattern' => '^wvpk',
809
- 'group' => 'audio',
810
- 'module' => 'wavpack',
811
- 'mime_type' => 'application/octet-stream',
812
- ),
813
-
814
-
815
- // Audio-Video formats
816
-
817
- // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
818
- 'asf' => array(
819
- 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
820
- 'group' => 'audio-video',
821
- 'module' => 'asf',
822
- 'mime_type' => 'video/x-ms-asf',
823
- 'iconv_req' => false,
824
- ),
825
-
826
- // BINK - audio/video - Bink / Smacker
827
- 'bink' => array(
828
- 'pattern' => '^(BIK|SMK)',
829
- 'group' => 'audio-video',
830
- 'module' => 'bink',
831
- 'mime_type' => 'application/octet-stream',
832
- ),
833
-
834
- // FLV - audio/video - FLash Video
835
- 'flv' => array(
836
- 'pattern' => '^FLV\x01',
837
- 'group' => 'audio-video',
838
- 'module' => 'flv',
839
- 'mime_type' => 'video/x-flv',
840
- ),
841
-
842
- // MKAV - audio/video - Mastroka
843
- 'matroska' => array(
844
- 'pattern' => '^\x1A\x45\xDF\xA3',
845
- 'group' => 'audio-video',
846
- 'module' => 'matroska',
847
- 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
848
- ),
849
-
850
- // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
851
- 'mpeg' => array(
852
- 'pattern' => '^\x00\x00\x01(\xBA|\xB3)',
853
- 'group' => 'audio-video',
854
- 'module' => 'mpeg',
855
- 'mime_type' => 'video/mpeg',
856
- ),
857
-
858
- // NSV - audio/video - Nullsoft Streaming Video (NSV)
859
- 'nsv' => array(
860
- 'pattern' => '^NSV[sf]',
861
- 'group' => 'audio-video',
862
- 'module' => 'nsv',
863
- 'mime_type' => 'application/octet-stream',
864
- ),
865
-
866
- // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
867
- 'ogg' => array(
868
- 'pattern' => '^OggS',
869
- 'group' => 'audio',
870
- 'module' => 'ogg',
871
- 'mime_type' => 'application/ogg',
872
- 'fail_id3' => 'WARNING',
873
- 'fail_ape' => 'WARNING',
874
- ),
875
-
876
- // QT - audio/video - Quicktime
877
- 'quicktime' => array(
878
- 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
879
- 'group' => 'audio-video',
880
- 'module' => 'quicktime',
881
- 'mime_type' => 'video/quicktime',
882
- ),
883
-
884
- // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
885
- 'riff' => array(
886
- 'pattern' => '^(RIFF|SDSS|FORM)',
887
- 'group' => 'audio-video',
888
- 'module' => 'riff',
889
- 'mime_type' => 'audio/x-wave',
890
- 'fail_ape' => 'WARNING',
891
- ),
892
-
893
- // Real - audio/video - RealAudio, RealVideo
894
- 'real' => array(
895
- 'pattern' => '^(\\.RMF|\\.ra)',
896
- 'group' => 'audio-video',
897
- 'module' => 'real',
898
- 'mime_type' => 'audio/x-realaudio',
899
- ),
900
-
901
- // SWF - audio/video - ShockWave Flash
902
- 'swf' => array(
903
- 'pattern' => '^(F|C)WS',
904
- 'group' => 'audio-video',
905
- 'module' => 'swf',
906
- 'mime_type' => 'application/x-shockwave-flash',
907
- ),
908
-
909
- // TS - audio/video - MPEG-2 Transport Stream
910
- 'ts' => array(
911
- 'pattern' => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern
912
- 'group' => 'audio-video',
913
- 'module' => 'ts',
914
- 'mime_type' => 'video/MP2T',
915
- ),
916
-
917
-
918
- // Still-Image formats
919
-
920
- // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
921
- 'bmp' => array(
922
- 'pattern' => '^BM',
923
- 'group' => 'graphic',
924
- 'module' => 'bmp',
925
- 'mime_type' => 'image/bmp',
926
- 'fail_id3' => 'ERROR',
927
- 'fail_ape' => 'ERROR',
928
- ),
929
-
930
- // GIF - still image - Graphics Interchange Format
931
- 'gif' => array(
932
- 'pattern' => '^GIF',
933
- 'group' => 'graphic',
934
- 'module' => 'gif',
935
- 'mime_type' => 'image/gif',
936
- 'fail_id3' => 'ERROR',
937
- 'fail_ape' => 'ERROR',
938
- ),
939
-
940
- // JPEG - still image - Joint Photographic Experts Group (JPEG)
941
- 'jpg' => array(
942
- 'pattern' => '^\xFF\xD8\xFF',
943
- 'group' => 'graphic',
944
- 'module' => 'jpg',
945
- 'mime_type' => 'image/jpeg',
946
- 'fail_id3' => 'ERROR',
947
- 'fail_ape' => 'ERROR',
948
- ),
949
-
950
- // PCD - still image - Kodak Photo CD
951
- 'pcd' => array(
952
- 'pattern' => '^.{2048}PCD_IPI\x00',
953
- 'group' => 'graphic',
954
- 'module' => 'pcd',
955
- 'mime_type' => 'image/x-photo-cd',
956
- 'fail_id3' => 'ERROR',
957
- 'fail_ape' => 'ERROR',
958
- ),
959
-
960
-
961
- // PNG - still image - Portable Network Graphics (PNG)
962
- 'png' => array(
963
- 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
964
- 'group' => 'graphic',
965
- 'module' => 'png',
966
- 'mime_type' => 'image/png',
967
- 'fail_id3' => 'ERROR',
968
- 'fail_ape' => 'ERROR',
969
- ),
970
-
971
-
972
- // SVG - still image - Scalable Vector Graphics (SVG)
973
- 'svg' => array(
974
- 'pattern' => '(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
975
- 'group' => 'graphic',
976
- 'module' => 'svg',
977
- 'mime_type' => 'image/svg+xml',
978
- 'fail_id3' => 'ERROR',
979
- 'fail_ape' => 'ERROR',
980
- ),
981
-
982
-
983
- // TIFF - still image - Tagged Information File Format (TIFF)
984
- 'tiff' => array(
985
- 'pattern' => '^(II\x2A\x00|MM\x00\x2A)',
986
- 'group' => 'graphic',
987
- 'module' => 'tiff',
988
- 'mime_type' => 'image/tiff',
989
- 'fail_id3' => 'ERROR',
990
- 'fail_ape' => 'ERROR',
991
- ),
992
-
993
-
994
- // EFAX - still image - eFax (TIFF derivative)
995
- 'efax' => array(
996
- 'pattern' => '^\xDC\xFE',
997
- 'group' => 'graphic',
998
- 'module' => 'efax',
999
- 'mime_type' => 'image/efax',
1000
- 'fail_id3' => 'ERROR',
1001
- 'fail_ape' => 'ERROR',
1002
- ),
1003
-
1004
-
1005
- // Data formats
1006
-
1007
- // ISO - data - International Standards Organization (ISO) CD-ROM Image
1008
- 'iso' => array(
1009
- 'pattern' => '^.{32769}CD001',
1010
- 'group' => 'misc',
1011
- 'module' => 'iso',
1012
- 'mime_type' => 'application/octet-stream',
1013
- 'fail_id3' => 'ERROR',
1014
- 'fail_ape' => 'ERROR',
1015
- 'iconv_req' => false,
1016
- ),
1017
-
1018
- // RAR - data - RAR compressed data
1019
- 'rar' => array(
1020
- 'pattern' => '^Rar\!',
1021
- 'group' => 'archive',
1022
- 'module' => 'rar',
1023
- 'mime_type' => 'application/octet-stream',
1024
- 'fail_id3' => 'ERROR',
1025
- 'fail_ape' => 'ERROR',
1026
- ),
1027
-
1028
- // SZIP - audio/data - SZIP compressed data
1029
- 'szip' => array(
1030
- 'pattern' => '^SZ\x0A\x04',
1031
- 'group' => 'archive',
1032
- 'module' => 'szip',
1033
- 'mime_type' => 'application/octet-stream',
1034
- 'fail_id3' => 'ERROR',
1035
- 'fail_ape' => 'ERROR',
1036
- ),
1037
-
1038
- // TAR - data - TAR compressed data
1039
- 'tar' => array(
1040
- 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
1041
- 'group' => 'archive',
1042
- 'module' => 'tar',
1043
- 'mime_type' => 'application/x-tar',
1044
- 'fail_id3' => 'ERROR',
1045
- 'fail_ape' => 'ERROR',
1046
- ),
1047
-
1048
- // GZIP - data - GZIP compressed data
1049
- 'gz' => array(
1050
- 'pattern' => '^\x1F\x8B\x08',
1051
- 'group' => 'archive',
1052
- 'module' => 'gzip',
1053
- 'mime_type' => 'application/x-gzip',
1054
- 'fail_id3' => 'ERROR',
1055
- 'fail_ape' => 'ERROR',
1056
- ),
1057
-
1058
- // ZIP - data - ZIP compressed data
1059
- 'zip' => array(
1060
- 'pattern' => '^PK\x03\x04',
1061
- 'group' => 'archive',
1062
- 'module' => 'zip',
1063
- 'mime_type' => 'application/zip',
1064
- 'fail_id3' => 'ERROR',
1065
- 'fail_ape' => 'ERROR',
1066
- ),
1067
-
1068
-
1069
- // Misc other formats
1070
-
1071
- // PAR2 - data - Parity Volume Set Specification 2.0
1072
- 'par2' => array (
1073
- 'pattern' => '^PAR2\x00PKT',
1074
- 'group' => 'misc',
1075
- 'module' => 'par2',
1076
- 'mime_type' => 'application/octet-stream',
1077
- 'fail_id3' => 'ERROR',
1078
- 'fail_ape' => 'ERROR',
1079
- ),
1080
-
1081
- // PDF - data - Portable Document Format
1082
- 'pdf' => array(
1083
- 'pattern' => '^\x25PDF',
1084
- 'group' => 'misc',
1085
- 'module' => 'pdf',
1086
- 'mime_type' => 'application/pdf',
1087
- 'fail_id3' => 'ERROR',
1088
- 'fail_ape' => 'ERROR',
1089
- ),
1090
-
1091
- // MSOFFICE - data - ZIP compressed data
1092
- 'msoffice' => array(
1093
- 'pattern' => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
1094
- 'group' => 'misc',
1095
- 'module' => 'msoffice',
1096
- 'mime_type' => 'application/octet-stream',
1097
- 'fail_id3' => 'ERROR',
1098
- 'fail_ape' => 'ERROR',
1099
- ),
1100
-
1101
- // CUE - data - CUEsheet (index to single-file disc images)
1102
- 'cue' => array(
1103
- 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
1104
- 'group' => 'misc',
1105
- 'module' => 'cue',
1106
- 'mime_type' => 'application/octet-stream',
1107
- ),
1108
-
1109
- );
1110
- }
1111
-
1112
- return $format_info;
 
 
 
 
 
 
 
1113
  }
1114
 
 
 
1115
 
1116
-
1117
- public function GetFileFormat(&$filedata, $filename='') {
1118
- // this function will determine the format of a file based on usually
1119
- // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
1120
- // and in the case of ISO CD image, 6 bytes offset 32kb from the start
1121
- // of the file).
1122
-
1123
- // Identify file format - loop through $format_info and detect with reg expr
1124
- foreach ($this->GetFileFormatArray() as $format_name => $info) {
1125
- // The /s switch on preg_match() forces preg_match() NOT to treat
1126
- // newline (0x0A) characters as special chars but do a binary match
1127
- if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) {
1128
- $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1129
- return $info;
1130
- }
1131
- }
1132
-
1133
-
1134
- if (preg_match('#\.mp[123a]$#i', $filename)) {
1135
- // Too many mp3 encoders on the market put gabage in front of mpeg files
1136
- // use assume format on these if format detection failed
1137
- $GetFileFormatArray = $this->GetFileFormatArray();
1138
- $info = $GetFileFormatArray['mp3'];
1139
  $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1140
  return $info;
1141
- } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
1142
- // there's not really a useful consistent "magic" at the beginning of .cue files to identify them
1143
- // so until I think of something better, just go by filename if all other format checks fail
1144
- // and verify there's at least one instance of "TRACK xx AUDIO" in the file
1145
- $GetFileFormatArray = $this->GetFileFormatArray();
1146
- $info = $GetFileFormatArray['cue'];
1147
- $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1148
- return $info;
1149
  }
1150
-
1151
- return false;
1152
  }
1153
 
1154
 
1155
- // converts array to $encoding charset from $this->encoding
1156
- public function CharConvert(&$array, $encoding) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1157
 
1158
- // identical encoding - end here
1159
- if ($encoding == $this->encoding) {
1160
- return;
1161
- }
1162
 
1163
- // loop thru array
1164
- foreach ($array as $key => $value) {
 
 
 
 
 
 
 
 
 
 
1165
 
1166
- // go recursive
1167
- if (is_array($value)) {
1168
- $this->CharConvert($array[$key], $encoding);
1169
- }
1170
 
1171
- // convert string
1172
- elseif (is_string($value)) {
1173
- $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
1174
- }
1175
  }
1176
- }
1177
 
1178
-
1179
- public function HandleAllTags() {
1180
-
1181
- // key name => array (tag name, character encoding)
1182
- static $tags;
1183
- if (empty($tags)) {
1184
- $tags = array(
1185
- 'asf' => array('asf' , 'UTF-16LE'),
1186
- 'midi' => array('midi' , 'ISO-8859-1'),
1187
- 'nsv' => array('nsv' , 'ISO-8859-1'),
1188
- 'ogg' => array('vorbiscomment' , 'UTF-8'),
1189
- 'png' => array('png' , 'UTF-8'),
1190
- 'tiff' => array('tiff' , 'ISO-8859-1'),
1191
- 'quicktime' => array('quicktime' , 'UTF-8'),
1192
- 'real' => array('real' , 'ISO-8859-1'),
1193
- 'vqf' => array('vqf' , 'ISO-8859-1'),
1194
- 'zip' => array('zip' , 'ISO-8859-1'),
1195
- 'riff' => array('riff' , 'ISO-8859-1'),
1196
- 'lyrics3' => array('lyrics3' , 'ISO-8859-1'),
1197
- 'id3v1' => array('id3v1' , $this->encoding_id3v1),
1198
- 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8
1199
- 'ape' => array('ape' , 'UTF-8'),
1200
- 'cue' => array('cue' , 'ISO-8859-1'),
1201
- 'matroska' => array('matroska' , 'UTF-8'),
1202
- 'flac' => array('vorbiscomment' , 'UTF-8'),
1203
- 'divxtag' => array('divx' , 'ISO-8859-1'),
1204
- 'iptc' => array('iptc' , 'ISO-8859-1'),
1205
- );
1206
  }
 
 
1207
 
1208
- // loop through comments array
1209
- foreach ($tags as $comment_name => $tagname_encoding_array) {
1210
- list($tag_name, $encoding) = $tagname_encoding_array;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1211
 
1212
- // fill in default encoding type if not already present
1213
- if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) {
1214
- $this->info[$comment_name]['encoding'] = $encoding;
1215
- }
1216
 
1217
- // copy comments if key name set
1218
- if (!empty($this->info[$comment_name]['comments'])) {
1219
- foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
1220
- foreach ($valuearray as $key => $value) {
1221
- if (is_string($value)) {
1222
- $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
1223
- }
1224
- if ($value) {
1225
- if (!is_numeric($key)) {
1226
- $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
1227
- } else {
1228
- $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
1229
- }
1230
- }
1231
  }
1232
- if ($tag_key == 'picture') {
1233
- unset($this->info[$comment_name]['comments'][$tag_key]);
 
 
 
 
1234
  }
1235
  }
1236
-
1237
- if (!isset($this->info['tags'][$tag_name])) {
1238
- // comments are set but contain nothing but empty strings, so skip
1239
- continue;
1240
  }
 
1241
 
1242
- if ($this->option_tags_html) {
1243
- foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
1244
- $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $encoding);
1245
- }
1246
- }
1247
 
1248
- // ID3v1 encoding detection hack start
1249
- // ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
1250
- // Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
1251
- if ($comment_name == 'id3v1') {
1252
- if ($encoding == 'ISO-8859-1') {
1253
- if (function_exists('iconv')) {
1254
- foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
1255
- foreach ($valuearray as $key => $value) {
1256
- if (preg_match('#^[\\x80-\\xFF]+$#', $value)) {
1257
- foreach (array('windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
1258
- if (@iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
1259
- $encoding = $id3v1_bad_encoding;
1260
- break 3;
1261
- }
1262
- }
1263
- }
1264
- }
1265
- }
1266
- }
1267
  }
 
1268
  }
1269
- // ID3v1 encoding detection hack end
1270
-
1271
- $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!
1272
  }
1273
 
1274
  }
1275
 
1276
- // pictures can take up a lot of space, and we don't need multiple copies of them
1277
- // let there be a single copy in [comments][picture], and not elsewhere
1278
- if (!empty($this->info['tags'])) {
1279
- $unset_keys = array('tags', 'tags_html');
1280
- foreach ($this->info['tags'] as $tagtype => $tagarray) {
1281
- foreach ($tagarray as $tagname => $tagdata) {
1282
- if ($tagname == 'picture') {
1283
- foreach ($tagdata as $key => $tagarray) {
1284
- $this->info['comments']['picture'][] = $tagarray;
1285
- if (isset($tagarray['data']) && isset($tagarray['image_mime'])) {
1286
- if (isset($this->info['tags'][$tagtype][$tagname][$key])) {
1287
- unset($this->info['tags'][$tagtype][$tagname][$key]);
1288
- }
1289
- if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) {
1290
- unset($this->info['tags_html'][$tagtype][$tagname][$key]);
1291
- }
1292
  }
1293
  }
1294
  }
1295
  }
1296
- foreach ($unset_keys as $unset_key) {
1297
- // remove possible empty keys from (e.g. [tags][id3v2][picture])
1298
- if (empty($this->info[$unset_key][$tagtype]['picture'])) {
1299
- unset($this->info[$unset_key][$tagtype]['picture']);
1300
- }
1301
- if (empty($this->info[$unset_key][$tagtype])) {
1302
- unset($this->info[$unset_key][$tagtype]);
1303
- }
1304
- if (empty($this->info[$unset_key])) {
1305
- unset($this->info[$unset_key]);
1306
- }
1307
- }
1308
- // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture])
1309
- if (isset($this->info[$tagtype]['comments']['picture'])) {
1310
- unset($this->info[$tagtype]['comments']['picture']);
1311
  }
1312
- if (empty($this->info[$tagtype]['comments'])) {
1313
- unset($this->info[$tagtype]['comments']);
1314
  }
1315
- if (empty($this->info[$tagtype])) {
1316
- unset($this->info[$tagtype]);
1317
  }
1318
  }
 
 
 
 
 
 
 
 
 
 
1319
  }
1320
- return true;
1321
  }
 
 
1322
 
1323
- public function getHashdata($algorithm) {
1324
- switch ($algorithm) {
1325
- case 'md5':
1326
- case 'sha1':
1327
- break;
1328
-
1329
- default:
1330
- return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
1331
- break;
1332
- }
1333
-
1334
- if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
1335
-
1336
- // We cannot get an identical md5_data value for Ogg files where the comments
1337
- // span more than 1 Ogg page (compared to the same audio data with smaller
1338
- // comments) using the normal getID3() method of MD5'ing the data between the
1339
- // end of the comments and the end of the file (minus any trailing tags),
1340
- // because the page sequence numbers of the pages that the audio data is on
1341
- // do not match. Under normal circumstances, where comments are smaller than
1342
- // the nominal 4-8kB page size, then this is not a problem, but if there are
1343
- // very large comments, the only way around it is to strip off the comment
1344
- // tags with vorbiscomment and MD5 that file.
1345
- // This procedure must be applied to ALL Ogg files, not just the ones with
1346
- // comments larger than 1 page, because the below method simply MD5's the
1347
- // whole file with the comments stripped, not just the portion after the
1348
- // comments block (which is the standard getID3() method.
1349
-
1350
- // The above-mentioned problem of comments spanning multiple pages and changing
1351
- // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
1352
- // currently vorbiscomment only works on OggVorbis files.
1353
-
1354
- if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
1355
-
1356
- $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
1357
- $this->info[$algorithm.'_data'] = false;
1358
-
1359
- } else {
1360
-
1361
- // Prevent user from aborting script
1362
- $old_abort = ignore_user_abort(true);
1363
 
1364
- // Create empty file
1365
- $empty = tempnam(GETID3_TEMP_DIR, 'getID3');
1366
- touch($empty);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1367
 
1368
- // Use vorbiscomment to make temp file without comments
1369
- $temp = tempnam(GETID3_TEMP_DIR, 'getID3');
1370
- $file = $this->info['filenamepath'];
1371
 
1372
- if (GETID3_OS_ISWINDOWS) {
 
1373
 
1374
- if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
1375
 
1376
- $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"';
1377
- $VorbisCommentError = `$commandline`;
1378
 
1379
- } else {
 
 
1380
 
1381
- $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
 
 
1382
 
1383
- }
1384
 
1385
- } else {
1386
 
1387
- $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
1388
- $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
1389
  $VorbisCommentError = `$commandline`;
1390
 
1391
- }
1392
-
1393
- if (!empty($VorbisCommentError)) {
1394
-
1395
- $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;
1396
- $this->info[$algorithm.'_data'] = false;
1397
-
1398
  } else {
1399
 
1400
- // Get hash of newly created file
1401
- switch ($algorithm) {
1402
- case 'md5':
1403
- $this->info[$algorithm.'_data'] = md5_file($temp);
1404
- break;
1405
 
1406
- case 'sha1':
1407
- $this->info[$algorithm.'_data'] = sha1_file($temp);
1408
- break;
1409
- }
1410
  }
1411
 
1412
- // Clean up
1413
- unlink($empty);
1414
- unlink($temp);
1415
 
1416
- // Reset abort setting
1417
- ignore_user_abort($old_abort);
1418
 
1419
  }
1420
 
1421
- } else {
1422
-
1423
- if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) {
1424
 
1425
- // get hash from part of file
1426
- $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
1427
 
1428
  } else {
1429
 
1430
- // get hash from whole file
1431
  switch ($algorithm) {
1432
  case 'md5':
1433
- $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']);
1434
  break;
1435
 
1436
  case 'sha1':
1437
- $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']);
1438
  break;
1439
  }
1440
  }
1441
 
 
 
 
 
 
 
 
1442
  }
1443
- return true;
1444
- }
1445
 
 
1446
 
1447
- public function ChannelsBitratePlaytimeCalculations() {
1448
 
1449
- // set channelmode on audio
1450
- if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
1451
- // ignore
1452
- } elseif ($this->info['audio']['channels'] == 1) {
1453
- $this->info['audio']['channelmode'] = 'mono';
1454
- } elseif ($this->info['audio']['channels'] == 2) {
1455
- $this->info['audio']['channelmode'] = 'stereo';
1456
- }
1457
 
1458
- // Calculate combined bitrate - audio + video
1459
- $CombinedBitrate = 0;
1460
- $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
1461
- $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
1462
- if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) {
1463
- $this->info['bitrate'] = $CombinedBitrate;
1464
- }
1465
- //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
1466
- // // for example, VBR MPEG video files cannot determine video bitrate:
1467
- // // should not set overall bitrate and playtime from audio bitrate only
1468
- // unset($this->info['bitrate']);
1469
- //}
1470
-
1471
- // video bitrate undetermined, but calculable
1472
- if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) {
1473
- // if video bitrate not set
1474
- if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) {
1475
- // AND if audio bitrate is set to same as overall bitrate
1476
- if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) {
1477
- // AND if playtime is set
1478
- if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) {
1479
- // AND if AV data offset start/end is known
1480
- // THEN we can calculate the video bitrate
1481
- $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']);
1482
- $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate'];
1483
- }
1484
- }
1485
- }
1486
- }
1487
 
1488
- if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
1489
- $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
1490
- }
 
 
1491
 
1492
- if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
1493
- $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
1494
- }
1495
- if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
1496
- if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
1497
- // audio only
1498
- $this->info['audio']['bitrate'] = $this->info['bitrate'];
1499
- } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
1500
- // video only
1501
- $this->info['video']['bitrate'] = $this->info['bitrate'];
1502
  }
1503
  }
1504
 
1505
- // Set playtime string
1506
- if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
1507
- $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
1508
- }
1509
  }
 
 
1510
 
 
1511
 
1512
- public function CalculateCompressionRatioVideo() {
1513
- if (empty($this->info['video'])) {
1514
- return false;
1515
- }
1516
- if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
1517
- return false;
1518
- }
1519
- if (empty($this->info['video']['bits_per_sample'])) {
1520
- return false;
1521
- }
1522
-
1523
- switch ($this->info['video']['dataformat']) {
1524
- case 'bmp':
1525
- case 'gif':
1526
- case 'jpeg':
1527
- case 'jpg':
1528
- case 'png':
1529
- case 'tiff':
1530
- $FrameRate = 1;
1531
- $PlaytimeSeconds = 1;
1532
- $BitrateCompressed = $this->info['filesize'] * 8;
1533
- break;
1534
 
1535
- default:
1536
- if (!empty($this->info['video']['frame_rate'])) {
1537
- $FrameRate = $this->info['video']['frame_rate'];
1538
- } else {
1539
- return false;
1540
- }
1541
- if (!empty($this->info['playtime_seconds'])) {
1542
- $PlaytimeSeconds = $this->info['playtime_seconds'];
1543
- } else {
1544
- return false;
1545
- }
1546
- if (!empty($this->info['video']['bitrate'])) {
1547
- $BitrateCompressed = $this->info['video']['bitrate'];
1548
- } else {
1549
- return false;
 
 
 
 
 
 
 
 
 
 
1550
  }
1551
- break;
1552
  }
1553
- $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;
1554
-
1555
- $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
1556
- return true;
1557
  }
1558
 
 
 
 
1559
 
1560
- public function CalculateCompressionRatioAudio() {
1561
- if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
1562
- return false;
 
 
 
 
 
 
 
1563
  }
1564
- $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
1565
 
1566
- if (!empty($this->info['audio']['streams'])) {
1567
- foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
1568
- if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
1569
- $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
1570
- }
1571
- }
1572
- }
1573
- return true;
1574
  }
 
1575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1576
 
1577
- public function CalculateReplayGain() {
1578
- if (isset($this->info['replay_gain'])) {
1579
- if (!isset($this->info['replay_gain']['reference_volume'])) {
1580
- $this->info['replay_gain']['reference_volume'] = (double) 89.0;
 
 
 
 
 
 
 
 
 
 
 
 
 
1581
  }
1582
- if (isset($this->info['replay_gain']['track']['adjustment'])) {
1583
- $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
 
 
1584
  }
1585
- if (isset($this->info['replay_gain']['album']['adjustment'])) {
1586
- $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
 
 
1587
  }
 
 
 
1588
 
1589
- if (isset($this->info['replay_gain']['track']['peak'])) {
1590
- $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
1591
- }
1592
- if (isset($this->info['replay_gain']['album']['peak'])) {
1593
- $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
1594
- }
1595
- }
1596
- return true;
 
 
1597
  }
 
1598
 
1599
- public function ProcessAudioStreams() {
1600
- if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
1601
- if (!isset($this->info['audio']['streams'])) {
1602
- foreach ($this->info['audio'] as $key => $value) {
1603
- if ($key != 'streams') {
1604
- $this->info['audio']['streams'][0][$key] = $value;
1605
- }
1606
- }
1607
  }
1608
  }
1609
- return true;
1610
  }
 
 
1611
 
1612
- public function getid3_tempnam() {
1613
- return tempnam($this->tempdir, 'gI3');
1614
- }
 
 
 
 
 
 
 
 
 
 
 
1615
 
1616
- public function include_module($name) {
1617
- //if (!file_exists($this->include_path.'module.'.$name.'.php')) {
1618
- if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
1619
- throw new getid3_exception('Required module.'.$name.'.php is missing.');
 
1620
  }
1621
- include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
1622
- return true;
1623
  }
1624
-
1625
  }
1626
- }
1627
-
1628
-
1629
- if( ! class_exists( 'getid3_handler' ) ){
1630
- abstract class getid3_handler {
1631
-
1632
- /**
1633
- * @var getID3
1634
- */
1635
- protected $getid3; // pointer
1636
-
1637
- protected $data_string_flag = false; // analyzing filepointer or string
1638
- protected $data_string = ''; // string to analyze
1639
- protected $data_string_position = 0; // seek position in string
1640
- protected $data_string_length = 0; // string length
1641
-
1642
- private $dependency_to = null;
1643
-
1644
 
1645
- public function __construct(getID3 $getid3, $call_module=null) {
1646
- $this->getid3 = $getid3;
1647
-
1648
- if ($call_module) {
1649
- $this->dependency_to = str_replace('getid3_', '', $call_module);
 
 
 
 
 
 
1650
  }
1651
  }
 
 
1652
 
 
 
 
 
 
 
1653
 
1654
- // Analyze from file pointer
1655
- abstract public function Analyze();
 
 
 
 
 
 
 
 
 
 
 
 
 
1656
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1657
 
1658
- // Analyze from string instead
1659
- public function AnalyzeString($string) {
1660
- // Enter string mode
1661
- $this->setStringMode($string);
1662
 
1663
- // Save info
1664
- $saved_avdataoffset = $this->getid3->info['avdataoffset'];
1665
- $saved_avdataend = $this->getid3->info['avdataend'];
1666
- $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call
1667
 
1668
- // Reset some info
1669
- $this->getid3->info['avdataoffset'] = 0;
1670
- $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1671
 
1672
- // Analyze
1673
- $this->Analyze();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1674
 
1675
- // Restore some info
1676
- $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
1677
- $this->getid3->info['avdataend'] = $saved_avdataend;
1678
- $this->getid3->info['filesize'] = $saved_filesize;
 
 
 
 
1679
 
1680
- // Exit string mode
1681
- $this->data_string_flag = false;
 
 
 
 
1682
  }
 
 
1683
 
1684
- public function setStringMode($string) {
1685
- $this->data_string_flag = true;
1686
- $this->data_string = $string;
1687
- $this->data_string_length = strlen($string);
 
 
 
 
 
 
 
1688
  }
1689
-
1690
- protected function ftell() {
1691
- if ($this->data_string_flag) {
1692
- return $this->data_string_position;
1693
- }
1694
- return ftell($this->getid3->fp);
1695
  }
1696
 
1697
- protected function fread($bytes) {
1698
- if ($this->data_string_flag) {
1699
- $this->data_string_position += $bytes;
1700
- return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
 
 
 
 
 
 
 
 
 
1701
  }
1702
- $pos = $this->ftell() + $bytes;
1703
- if (!getid3_lib::intValueSupported($pos)) {
1704
- throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
1705
- }
1706
- return fread($this->getid3->fp, $bytes);
1707
- }
 
1708
 
1709
- protected function fseek($bytes, $whence=SEEK_SET) {
1710
- if ($this->data_string_flag) {
1711
- switch ($whence) {
1712
- case SEEK_SET:
1713
- $this->data_string_position = $bytes;
1714
- break;
 
 
 
 
 
 
 
 
1715
 
1716
- case SEEK_CUR:
1717
- $this->data_string_position += $bytes;
1718
- break;
1719
 
1720
- case SEEK_END:
1721
- $this->data_string_position = $this->data_string_length + $bytes;
1722
- break;
1723
- }
1724
- return 0;
1725
- } else {
1726
- $pos = $bytes;
1727
- if ($whence == SEEK_CUR) {
1728
- $pos = $this->ftell() + $bytes;
1729
- } elseif ($whence == SEEK_END) {
1730
- $pos = $this->getid3->info['filesize'] + $bytes;
1731
- }
1732
- if (!getid3_lib::intValueSupported($pos)) {
1733
- throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
1734
- }
1735
  }
1736
- return fseek($this->getid3->fp, $bytes, $whence);
1737
- }
1738
-
1739
- protected function feof() {
1740
- if ($this->data_string_flag) {
1741
- return $this->data_string_position >= $this->data_string_length;
 
 
 
 
1742
  }
1743
- return feof($this->getid3->fp);
1744
- }
1745
-
1746
- final protected function isDependencyFor($module) {
1747
- return $this->dependency_to == $module;
1748
- }
1749
-
1750
- protected function error($text) {
1751
- $this->getid3->info['error'][] = $text;
1752
-
1753
- return false;
1754
  }
 
 
1755
 
1756
- protected function warning($text) {
1757
- return $this->getid3->warning($text);
 
 
 
 
1758
  }
 
 
1759
 
1760
- protected function notice($text) {
1761
- // does nothing for now
1762
- }
 
 
 
 
 
1763
 
1764
- public function saveAttachment($name, $offset, $length, $image_mime=null) {
1765
- try {
 
 
 
 
 
1766
 
1767
- // do not extract at all
1768
- if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
1769
 
1770
- $attachment = null; // do not set any
 
 
 
 
 
 
 
1771
 
1772
- // extract to return array
1773
- } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
 
 
 
 
1774
 
1775
- $this->fseek($offset);
1776
- $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory
1777
- if ($attachment === false || strlen($attachment) != $length) {
1778
- throw new Exception('failed to read attachment data');
1779
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1780
 
1781
- // assume directory path is given
1782
- } else {
1783
 
1784
- // set up destination path
1785
- $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1786
- if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory
1787
- throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
1788
- }
1789
- $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
1790
 
1791
- // create dest file
1792
- if (($fp_dest = fopen($dest, 'wb')) == false) {
1793
- throw new Exception('failed to create file '.$dest);
1794
- }
1795
 
1796
- // copy data
1797
- $this->fseek($offset);
1798
- $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
1799
- $bytesleft = $length;
1800
- while ($bytesleft > 0) {
1801
- if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) {
1802
- throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
1803
- }
1804
- $bytesleft -= $byteswritten;
1805
  }
1806
-
1807
- fclose($fp_dest);
1808
- $attachment = $dest;
1809
-
1810
  }
1811
 
1812
- } catch (Exception $e) {
 
1813
 
1814
- // close and remove dest file if created
1815
- if (isset($fp_dest) && is_resource($fp_dest)) {
1816
- fclose($fp_dest);
1817
- unlink($dest);
1818
- }
1819
 
1820
- // do not set any is case of error
1821
- $attachment = null;
1822
- $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage());
1823
 
 
 
 
1824
  }
1825
 
1826
- // seek to the end of attachment
1827
- $this->fseek($offset + $length);
 
 
 
 
 
1828
 
1829
- return $attachment;
1830
  }
1831
 
 
 
 
 
1832
  }
 
1833
  }
1834
 
1835
 
1836
- if ( ! class_exists ( "getid3_exception" ) ) {
1837
- class getid3_exception extends Exception
1838
- {
1839
- public $message;
1840
- }
1841
  }
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
+ // available at https://github.com/JamesHeinrich/getID3 //
5
+ // or https://www.getid3.org //
6
+ // or http://getid3.sourceforge.net //
 
7
  // //
8
  // Please see readme.txt for more information //
9
  // ///
21
  if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
22
  define('IMG_JPG', IMAGETYPE_JPEG);
23
  }
24
+ if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
25
+ define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
26
+ }
27
+
28
+ /*
29
+ https://www.getid3.org/phpBB3/viewtopic.php?t=2114
30
+ If you are running into a the problem where filenames with special characters are being handled
31
+ incorrectly by external helper programs (e.g. metaflac), notably with the special characters removed,
32
+ and you are passing in the filename in UTF8 (typically via a HTML form), try uncommenting this line:
33
+ */
34
+ //setlocale(LC_CTYPE, 'en_US.UTF-8');
35
 
36
  // attempt to define temp dir as something flexible but reliable
37
  $temp_dir = ini_get('upload_tmp_dir');
78
 
79
  // End: Defines
80
 
 
 
 
 
 
 
 
 
81
 
82
+ class getID3
83
+ {
84
+ /*
85
+ * Settings
86
+ */
87
+
88
+ /**
89
+ * CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
90
+ *
91
+ * @var string
92
+ */
93
+ public $encoding = 'UTF-8';
94
+
95
+ /**
96
+ * Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
97
+ *
98
+ * @var string
99
+ */
100
+ public $encoding_id3v1 = 'ISO-8859-1';
101
+
102
+ /*
103
+ * Optional tag checks - disable for speed.
104
+ */
105
+
106
+ /**
107
+ * Read and process ID3v1 tags
108
+ *
109
+ * @var bool
110
+ */
111
+ public $option_tag_id3v1 = true;
112
+
113
+ /**
114
+ * Read and process ID3v2 tags
115
+ *
116
+ * @var bool
117
+ */
118
+ public $option_tag_id3v2 = true;
119
+
120
+ /**
121
+ * Read and process Lyrics3 tags
122
+ *
123
+ * @var bool
124
+ */
125
+ public $option_tag_lyrics3 = true;
126
+
127
+ /**
128
+ * Read and process APE tags
129
+ *
130
+ * @var bool
131
+ */
132
+ public $option_tag_apetag = true;
133
+
134
+ /**
135
+ * Copy tags to root key 'tags' and encode to $this->encoding
136
+ *
137
+ * @var bool
138
+ */
139
+ public $option_tags_process = true;
140
+
141
+ /**
142
+ * Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
143
+ *
144
+ * @var bool
145
+ */
146
+ public $option_tags_html = true;
147
+
148
+ /*
149
+ * Optional tag/comment calculations
150
+ */
151
+
152
+ /**
153
+ * Calculate additional info such as bitrate, channelmode etc
154
+ *
155
+ * @var bool
156
+ */
157
+ public $option_extra_info = true;
158
+
159
+ /*
160
+ * Optional handling of embedded attachments (e.g. images)
161
+ */
162
+
163
+ /**
164
+ * Defaults to true (ATTACHMENTS_INLINE) for backward compatibility
165
+ *
166
+ * @var bool|string
167
+ */
168
+ public $option_save_attachments = true;
169
+
170
+ /*
171
+ * Optional calculations
172
+ */
173
+
174
+ /**
175
+ * Get MD5 sum of data part - slow
176
+ *
177
+ * @var bool
178
+ */
179
+ public $option_md5_data = false;
180
+
181
+ /**
182
+ * Use MD5 of source file if availble - only FLAC and OptimFROG
183
+ *
184
+ * @var bool
185
+ */
186
+ public $option_md5_data_source = false;
187
+
188
+ /**
189
+ * Get SHA1 sum of data part - slow
190
+ *
191
+ * @var bool
192
+ */
193
+ public $option_sha1_data = false;
194
+
195
+ /**
196
+ * Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on
197
+ * PHP_INT_MAX)
198
+ *
199
+ * @var bool|null
200
+ */
201
+ public $option_max_2gb_check;
202
+
203
+ /**
204
+ * Read buffer size in bytes
205
+ *
206
+ * @var int
207
+ */
208
+ public $option_fread_buffer_size = 32768;
209
+
210
+ // Public variables
211
+
212
+ /**
213
+ * Filename of file being analysed.
214
+ *
215
+ * @var string
216
+ */
217
+ public $filename;
218
+
219
+ /**
220
+ * Filepointer to file being analysed.
221
+ *
222
+ * @var resource
223
+ */
224
+ public $fp;
225
+
226
+ /**
227
+ * Result array.
228
+ *
229
+ * @var array
230
+ */
231
+ public $info;
232
+
233
+ /**
234
+ * @var string
235
+ */
236
+ public $tempdir = GETID3_TEMP_DIR;
237
+
238
+ /**
239
+ * @var int
240
+ */
241
+ public $memory_limit = 0;
242
+
243
+ /**
244
+ * @var string
245
+ */
246
+ protected $startup_error = '';
247
+
248
+ /**
249
+ * @var string
250
+ */
251
+ protected $startup_warning = '';
252
+
253
+ const VERSION = '1.9.17-201902071234';
254
+ const FREAD_BUFFER_SIZE = 32768;
255
+
256
+ const ATTACHMENTS_NONE = false;
257
+ const ATTACHMENTS_INLINE = true;
258
+
259
+ public function __construct() {
260
+
261
+ // Check for PHP version
262
+ $required_php_version = '5.3.0';
263
+ if (version_compare(PHP_VERSION, $required_php_version, '<')) {
264
+ $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION."\n";
265
+ return;
266
+ }
267
 
268
+ // Check memory
269
+ $this->memory_limit = ini_get('memory_limit');
270
+ if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
271
+ // could be stored as "16M" rather than 16777216 for example
272
+ $this->memory_limit = $matches[1] * 1048576;
273
+ } elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
274
+ // could be stored as "2G" rather than 2147483648 for example
275
+ $this->memory_limit = $matches[1] * 1073741824;
276
+ }
277
+ if ($this->memory_limit <= 0) {
278
+ // memory limits probably disabled
279
+ } elseif ($this->memory_limit <= 4194304) {
280
+ $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'."\n";
281
+ } elseif ($this->memory_limit <= 12582912) {
282
+ $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'."\n";
283
+ }
284
 
285
+ // Check safe_mode off
286
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
287
+ $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
288
+ }
289
 
290
+ if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
291
+ // http://php.net/manual/en/mbstring.overload.php
292
+ // "mbstring.func_overload in php.ini is a positive value that represents a combination of bitmasks specifying the categories of functions to be overloaded. It should be set to 1 to overload the mail() function. 2 for string functions, 4 for regular expression functions"
293
+ // getID3 cannot run when string functions are overloaded. It doesn't matter if mail() or ereg* functions are overloaded since getID3 does not use those.
294
+ $this->startup_error .= 'WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", getID3 cannot run with this setting (bitmask 2 (string functions) cannot be set). Recommended to disable entirely.'."\n";
295
+ }
296
 
297
+ // Check for magic_quotes_runtime
298
+ if (function_exists('get_magic_quotes_runtime')) {
299
+ if (get_magic_quotes_runtime()) {
300
+ $this->startup_error .= 'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'."\n";
 
301
  }
302
+ }
303
 
304
+ // Check for magic_quotes_gpc
305
+ if (function_exists('magic_quotes_gpc')) {
306
+ if (get_magic_quotes_gpc()) {
307
+ $this->startup_error .= 'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'."\n";
 
308
  }
309
+ }
310
 
311
+ // Load support library
312
+ if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
313
+ $this->startup_error .= 'getid3.lib.php is missing or corrupt'."\n";
314
+ }
315
 
316
+ if ($this->option_max_2gb_check === null) {
317
+ $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
318
+ }
319
 
320
 
321
+ // Needed for Windows only:
322
+ // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
323
+ // as well as other helper functions such as head, tail, md5sum, etc
324
+ // This path cannot contain spaces, but the below code will attempt to get the
325
+ // 8.3-equivalent path automatically
326
+ // IMPORTANT: This path must include the trailing slash
327
+ if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
328
+
329
+ $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
330
+
331
+ if (!is_dir($helperappsdir)) {
332
+ $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'."\n";
333
+ } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
334
+ $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
335
+ $path_so_far = array();
336
+ foreach ($DirPieces as $key => $value) {
337
+ if (strpos($value, ' ') !== false) {
338
+ if (!empty($path_so_far)) {
339
+ $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
340
+ $dir_listing = `$commandline`;
341
+ $lines = explode("\n", $dir_listing);
342
+ foreach ($lines as $line) {
343
+ $line = trim($line);
344
+ if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
345
+ list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
346
+ if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
347
+ $value = $shortname;
 
348
  }
349
  }
 
 
350
  }
351
+ } else {
352
+ $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.'."\n";
353
  }
 
354
  }
355
+ $path_so_far[] = $value;
356
  }
357
+ $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
358
  }
359
+ define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
 
360
  }
361
 
362
+ if (!empty($this->startup_error)) {
363
+ echo $this->startup_error;
364
+ throw new getid3_exception($this->startup_error);
365
  }
366
+ }
367
 
368
+ /**
369
+ * @return string
370
+ */
371
+ public function version() {
372
+ return self::VERSION;
373
+ }
374
 
375
+ /**
376
+ * @return int
377
+ */
378
+ public function fread_buffer_size() {
379
+ return $this->option_fread_buffer_size;
380
+ }
381
 
382
+ /**
383
+ * @param array $optArray
384
+ *
385
+ * @return bool
386
+ */
387
+ public function setOption($optArray) {
388
+ if (!is_array($optArray) || empty($optArray)) {
389
+ return false;
390
+ }
391
+ foreach ($optArray as $opt => $val) {
392
+ if (isset($this->$opt) === false) {
393
+ continue;
394
  }
395
+ $this->$opt = $val;
396
  }
397
+ return true;
398
+ }
399
 
400
+ /**
401
+ * @param string $filename
402
+ * @param int $filesize
403
+ *
404
+ * @return bool
405
+ *
406
+ * @throws getid3_exception
407
+ */
408
+ public function openfile($filename, $filesize=null, $fp=null) {
409
+ try {
410
+ if (!empty($this->startup_error)) {
411
+ throw new getid3_exception($this->startup_error);
412
+ }
413
+ if (!empty($this->startup_warning)) {
414
+ foreach (explode("\n", $this->startup_warning) as $startup_warning) {
415
+ $this->warning($startup_warning);
416
  }
417
+ }
418
 
419
+ // init result array and set parameters
420
+ $this->filename = $filename;
421
+ $this->info = array();
422
+ $this->info['GETID3_VERSION'] = $this->version();
423
+ $this->info['php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit : false);
424
 
425
+ // remote files not supported
426
+ if (preg_match('#^(ht|f)tp://#', $filename)) {
427
+ throw new getid3_exception('Remote files are not supported - please copy the file locally first');
428
+ }
429
 
430
+ $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
431
+ //$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
432
 
433
+ // open local file
434
+ //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720
435
+ if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) {
436
+ $this->fp = $fp;
437
+ } elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
438
+ // great
439
+ } else {
440
+ $errormessagelist = array();
441
+ if (!is_readable($filename)) {
442
+ $errormessagelist[] = '!is_readable';
443
+ }
444
+ if (!is_file($filename)) {
445
+ $errormessagelist[] = '!is_file';
446
+ }
447
+ if (!file_exists($filename)) {
448
+ $errormessagelist[] = '!file_exists';
449
+ }
450
+ if (empty($errormessagelist)) {
451
+ $errormessagelist[] = 'fopen failed';
452
  }
453
+ throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
454
+ }
455
 
456
+ $this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename));
457
+ // set redundant parameters - might be needed in some include file
458
+ // filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
459
+ $filename = str_replace('\\', '/', $filename);
460
+ $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
461
+ $this->info['filename'] = getid3_lib::mb_basename($filename);
462
+ $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
463
+
464
+ // set more parameters
465
+ $this->info['avdataoffset'] = 0;
466
+ $this->info['avdataend'] = $this->info['filesize'];
467
+ $this->info['fileformat'] = ''; // filled in later
468
+ $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used
469
+ $this->info['video']['dataformat'] = ''; // filled in later, unset if not used
470
+ $this->info['tags'] = array(); // filled in later, unset if not used
471
+ $this->info['error'] = array(); // filled in later, unset if not used
472
+ $this->info['warning'] = array(); // filled in later, unset if not used
473
+ $this->info['comments'] = array(); // filled in later, unset if not used
474
+ $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired
475
+
476
+ // option_max_2gb_check
477
+ if ($this->option_max_2gb_check) {
478
+ // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
479
+ // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
480
+ // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
481
+ $fseek = fseek($this->fp, 0, SEEK_END);
482
+ if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
483
+ ($this->info['filesize'] < 0) ||
484
+ (ftell($this->fp) < 0)) {
485
  $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']);
486
 
487
  if ($real_filesize === false) {
491
  } elseif (getid3_lib::intValueSupported($real_filesize)) {
492
  unset($this->info['filesize']);
493
  fclose($this->fp);
494
+ throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB, please report to info@getid3.org');
495
  }
496
  $this->info['filesize'] = $real_filesize;
497
+ $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB) and is not properly supported by PHP.');
 
498
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  }
500
+
501
+ return true;
502
+
503
+ } catch (Exception $e) {
504
+ $this->error($e->getMessage());
505
  }
506
+ return false;
507
+ }
508
 
509
+ /**
510
+ * analyze file
511
+ *
512
+ * @param string $filename
513
+ * @param int $filesize
514
+ * @param string $original_filename
515
+ *
516
+ * @return array
517
+ */
518
+ public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
519
+ try {
520
+ if (!$this->openfile($filename, $filesize, $fp)) {
521
+ return $this->info;
522
+ }
523
 
524
+ // Handle tags
525
+ foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
526
+ $option_tag = 'option_tag_'.$tag_name;
527
+ if ($this->$option_tag) {
528
+ $this->include_module('tag.'.$tag_name);
529
+ try {
530
+ $tag_class = 'getid3_'.$tag_name;
531
+ $tag = new $tag_class($this);
532
+ $tag->Analyze();
 
 
 
 
533
  }
534
+ catch (getid3_exception $e) {
535
+ throw $e;
 
 
 
 
 
536
  }
537
  }
538
+ }
539
+ if (isset($this->info['id3v2']['tag_offset_start'])) {
540
+ $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']);
541
+ }
542
+ foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
543
+ if (isset($this->info[$tag_key]['tag_offset_start'])) {
544
+ $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']);
 
 
 
 
545
  }
546
+ }
547
 
548
+ // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
549
+ if (!$this->option_tag_id3v2) {
550
+ fseek($this->fp, 0);
551
+ $header = fread($this->fp, 10);
552
+ if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
553
+ $this->info['id3v2']['header'] = true;
554
+ $this->info['id3v2']['majorversion'] = ord($header{3});
555
+ $this->info['id3v2']['minorversion'] = ord($header{4});
556
+ $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
 
 
557
  }
558
+ }
559
 
560
+ // read 32 kb file data
561
+ fseek($this->fp, $this->info['avdataoffset']);
562
+ $formattest = fread($this->fp, 32774);
 
 
 
 
 
 
563
 
564
+ // determine format
565
+ $determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename));
 
 
 
 
 
 
 
566
 
567
+ // unable to determine file format
568
+ if (!$determined_format) {
569
+ fclose($this->fp);
570
+ return $this->error('unable to determine file format');
571
+ }
572
 
573
+ // check for illegal ID3 tags
574
+ if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
575
+ if ($determined_format['fail_id3'] === 'ERROR') {
576
  fclose($this->fp);
577
+ return $this->error('ID3 tags not allowed on this file type.');
578
+ } elseif ($determined_format['fail_id3'] === 'WARNING') {
579
+ $this->warning('ID3 tags not allowed on this file type.');
580
  }
581
+ }
582
 
583
+ // check for illegal APE tags
584
+ if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
585
+ if ($determined_format['fail_ape'] === 'ERROR') {
586
+ fclose($this->fp);
587
+ return $this->error('APE tags not allowed on this file type.');
588
+ } elseif ($determined_format['fail_ape'] === 'WARNING') {
589
+ $this->warning('APE tags not allowed on this file type.');
 
 
 
590
  }
591
+ }
592
 
593
+ // set mime type
594
+ $this->info['mime_type'] = $determined_format['mime_type'];
 
 
 
 
 
 
 
 
 
595
 
596
+ // supported format signature pattern detected, but module deleted
597
+ if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
598
  fclose($this->fp);
599
+ return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
600
+ }
601
 
602
+ // module requires mb_convert_encoding/iconv support
603
+ // Check encoding/iconv support
604
+ if (!empty($determined_format['iconv_req']) && !function_exists('mb_convert_encoding') && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
605
+ $errormessage = 'mb_convert_encoding() or iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
606
+ if (GETID3_OS_ISWINDOWS) {
607
+ $errormessage .= 'PHP does not have mb_convert_encoding() or iconv() support. Please enable php_mbstring.dll / php_iconv.dll in php.ini, and copy php_mbstring.dll / iconv.dll from c:/php/dlls to c:/windows/system32';
608
+ } else {
609
+ $errormessage .= 'PHP is not compiled with mb_convert_encoding() or iconv() support. Please recompile with the --enable-mbstring / --with-iconv switch';
610
  }
611
+ return $this->error($errormessage);
612
+ }
613
 
614
+ // include module
615
+ include_once(GETID3_INCLUDEPATH.$determined_format['include']);
 
 
 
 
 
 
616
 
617
+ // instantiate module class
618
+ $class_name = 'getid3_'.$determined_format['module'];
619
+ if (!class_exists($class_name)) {
620
+ return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
621
+ }
622
+ $class = new $class_name($this);
623
+ $class->Analyze();
624
+ unset($class);
625
 
626
+ // close file
627
+ fclose($this->fp);
 
 
628
 
629
+ // process all tags - copy to 'tags' and convert charsets
630
+ if ($this->option_tags_process) {
631
+ $this->HandleAllTags();
632
+ }
633
 
634
+ // perform more calculations
635
+ if ($this->option_extra_info) {
636
+ $this->ChannelsBitratePlaytimeCalculations();
637
+ $this->CalculateCompressionRatioVideo();
638
+ $this->CalculateCompressionRatioAudio();
639
+ $this->CalculateReplayGain();
640
+ $this->ProcessAudioStreams();
641
  }
642
 
643
+ // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
644
+ if ($this->option_md5_data) {
645
+ // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
646
+ if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
647
+ $this->getHashdata('md5');
648
+ }
649
+ }
650
 
651
+ // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
652
+ if ($this->option_sha1_data) {
653
+ $this->getHashdata('sha1');
654
+ }
655
 
656
+ // remove undesired keys
 
657
  $this->CleanUp();
658
+
659
+ } catch (Exception $e) {
660
+ $this->error('Caught exception: '.$e->getMessage());
 
 
661
  }
662
 
663
+ // return info array
664
+ return $this->info;
665
+ }
666
 
667
+
668
+ /**
669
+ * Error handling.
670
+ *
671
+ * @param string $message
672
+ *
673
+ * @return array
674
+ */
675
+ public function error($message) {
676
+ $this->CleanUp();
677
+ if (!isset($this->info['error'])) {
678
+ $this->info['error'] = array();
679
  }
680
+ $this->info['error'][] = $message;
681
+ return $this->info;
682
+ }
683
 
684
 
685
+ /**
686
+ * Warning handling.
687
+ *
688
+ * @param string $message
689
+ *
690
+ * @return bool
691
+ */
692
+ public function warning($message) {
693
+ $this->info['warning'][] = $message;
694
+ return true;
695
+ }
696
 
 
 
 
 
 
 
 
 
 
 
697
 
698
+ /**
699
+ * @return bool
700
+ */
701
+ private function CleanUp() {
702
+
703
+ // remove possible empty keys
704
+ $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
705
+ foreach ($AVpossibleEmptyKeys as $dummy => $key) {
706
+ if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
707
+ unset($this->info['audio'][$key]);
708
+ }
709
+ if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) {
710
+ unset($this->info['video'][$key]);
711
  }
712
+ }
713
 
714
+ // remove empty root keys
715
+ if (!empty($this->info)) {
716
+ foreach ($this->info as $key => $value) {
717
+ if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) {
718
+ unset($this->info[$key]);
 
 
719
  }
720
  }
721
+ }
722
 
723
+ // remove meaningless entries from unknown-format files
724
+ if (empty($this->info['fileformat'])) {
725
+ if (isset($this->info['avdataoffset'])) {
726
+ unset($this->info['avdataoffset']);
727
  }
728
+ if (isset($this->info['avdataend'])) {
729
+ unset($this->info['avdataend']);
730
  }
731
+ }
732
 
733
+ // remove possible duplicated identical entries
734
+ if (!empty($this->info['error'])) {
735
+ $this->info['error'] = array_values(array_unique($this->info['error']));
 
736
  }
737
+ if (!empty($this->info['warning'])) {
738
+ $this->info['warning'] = array_values(array_unique($this->info['warning']));
739
+ }
740
+
741
+ // remove "global variable" type keys
742
+ unset($this->info['php_memory_limit']);
743
 
744
+ return true;
745
+ }
746
 
747
+ /**
748
+ * Return array containing information about all supported formats.
749
+ *
750
+ * @return array
751
+ */
752
+ public function GetFileFormatArray() {
753
+ static $format_info = array();
754
+ if (empty($format_info)) {
755
+ $format_info = array(
756
+
757
+ // Audio formats
758
+
759
+ // AC-3 - audio - Dolby AC-3 / Dolby Digital
760
+ 'ac3' => array(
761
+ 'pattern' => '^\\x0B\\x77',
762
+ 'group' => 'audio',
763
+ 'module' => 'ac3',
764
+ 'mime_type' => 'audio/ac3',
765
+ ),
766
+
767
+ // AAC - audio - Advanced Audio Coding (AAC) - ADIF format
768
+ 'adif' => array(
769
+ 'pattern' => '^ADIF',
770
+ 'group' => 'audio',
771
+ 'module' => 'aac',
772
+ 'mime_type' => 'audio/aac',
773
+ 'fail_ape' => 'WARNING',
774
+ ),
775
+
776
+ /*
777
+ // AA - audio - Audible Audiobook
778
+ 'aa' => array(
779
+ 'pattern' => '^.{4}\\x57\\x90\\x75\\x36',
780
+ 'group' => 'audio',
781
+ 'module' => 'aa',
782
+ 'mime_type' => 'audio/audible',
783
+ ),
784
+ */
785
+ // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
786
+ 'adts' => array(
787
+ 'pattern' => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]',
788
+ 'group' => 'audio',
789
+ 'module' => 'aac',
790
+ 'mime_type' => 'audio/aac',
791
+ 'fail_ape' => 'WARNING',
792
+ ),
793
+
794
+
795
+ // AU - audio - NeXT/Sun AUdio (AU)
796
+ 'au' => array(
797
+ 'pattern' => '^\\.snd',
798
+ 'group' => 'audio',
799
+ 'module' => 'au',
800
+ 'mime_type' => 'audio/basic',
801
+ ),
802
+
803
+ // AMR - audio - Adaptive Multi Rate
804
+ 'amr' => array(
805
+ 'pattern' => '^\\x23\\x21AMR\\x0A', // #!AMR[0A]
806
+ 'group' => 'audio',
807
+ 'module' => 'amr',
808
+ 'mime_type' => 'audio/amr',
809
+ ),
810
+
811
+ // AVR - audio - Audio Visual Research
812
+ 'avr' => array(
813
+ 'pattern' => '^2BIT',
814
+ 'group' => 'audio',
815
+ 'module' => 'avr',
816
+ 'mime_type' => 'application/octet-stream',
817
+ ),
818
+
819
+ // BONK - audio - Bonk v0.9+
820
+ 'bonk' => array(
821
+ 'pattern' => '^\\x00(BONK|INFO|META| ID3)',
822
+ 'group' => 'audio',
823
+ 'module' => 'bonk',
824
+ 'mime_type' => 'audio/xmms-bonk',
825
+ ),
826
+
827
+ // DSF - audio - Direct Stream Digital (DSD) Storage Facility files (DSF) - https://en.wikipedia.org/wiki/Direct_Stream_Digital
828
+ 'dsf' => array(
829
+ 'pattern' => '^DSD ', // including trailing space: 44 53 44 20
830
+ 'group' => 'audio',
831
+ 'module' => 'dsf',
832
+ 'mime_type' => 'audio/dsd',
833
+ ),
834
+
835
+ // DSS - audio - Digital Speech Standard
836
+ 'dss' => array(
837
+ 'pattern' => '^[\\x02-\\x06]ds[s2]',
838
+ 'group' => 'audio',
839
+ 'module' => 'dss',
840
+ 'mime_type' => 'application/octet-stream',
841
+ ),
842
+
843
+ // DTS - audio - Dolby Theatre System
844
+ 'dts' => array(
845
+ 'pattern' => '^\\x7F\\xFE\\x80\\x01',
846
+ 'group' => 'audio',
847
+ 'module' => 'dts',
848
+ 'mime_type' => 'audio/dts',
849
+ ),
850
+
851
+ // FLAC - audio - Free Lossless Audio Codec
852
+ 'flac' => array(
853
+ 'pattern' => '^fLaC',
854
+ 'group' => 'audio',
855
+ 'module' => 'flac',
856
+ 'mime_type' => 'audio/flac',
857
+ ),
858
+
859
+ // LA - audio - Lossless Audio (LA)
860
+ 'la' => array(
861
+ 'pattern' => '^LA0[2-4]',
862
+ 'group' => 'audio',
863
+ 'module' => 'la',
864
+ 'mime_type' => 'application/octet-stream',
865
+ ),
866
+
867
+ // LPAC - audio - Lossless Predictive Audio Compression (LPAC)
868
+ 'lpac' => array(
869
+ 'pattern' => '^LPAC',
870
+ 'group' => 'audio',
871
+ 'module' => 'lpac',
872
+ 'mime_type' => 'application/octet-stream',
873
+ ),
874
+
875
+ // MIDI - audio - MIDI (Musical Instrument Digital Interface)
876
+ 'midi' => array(
877
+ 'pattern' => '^MThd',
878
+ 'group' => 'audio',
879
+ 'module' => 'midi',
880
+ 'mime_type' => 'audio/midi',
881
+ ),
882
+
883
+ // MAC - audio - Monkey's Audio Compressor
884
+ 'mac' => array(
885
+ 'pattern' => '^MAC ',
886
+ 'group' => 'audio',
887
+ 'module' => 'monkey',
888
+ 'mime_type' => 'audio/x-monkeys-audio',
889
+ ),
890
 
891
  // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
892
  // // MOD - audio - MODule (assorted sub-formats)
898
  // 'mime_type' => 'audio/mod',
899
  // ),
900
 
901
+ // MOD - audio - MODule (Impulse Tracker)
902
+ 'it' => array(
903
+ 'pattern' => '^IMPM',
904
+ 'group' => 'audio',
905
+ 'module' => 'mod',
906
+ //'option' => 'it',
907
+ 'mime_type' => 'audio/it',
908
+ ),
909
+
910
+ // MOD - audio - MODule (eXtended Module, various sub-formats)
911
+ 'xm' => array(
912
+ 'pattern' => '^Extended Module',
913
+ 'group' => 'audio',
914
+ 'module' => 'mod',
915
+ //'option' => 'xm',
916
+ 'mime_type' => 'audio/xm',
917
+ ),
918
+
919
+ // MOD - audio - MODule (ScreamTracker)
920
+ 's3m' => array(
921
+ 'pattern' => '^.{44}SCRM',
922
+ 'group' => 'audio',
923
+ 'module' => 'mod',
924
+ //'option' => 's3m',
925
+ 'mime_type' => 'audio/s3m',
926
+ ),
927
+
928
+ // MPC - audio - Musepack / MPEGplus
929
+ 'mpc' => array(
930
+ 'pattern' => '^(MPCK|MP\\+|[\\x00\\x01\\x10\\x11\\x40\\x41\\x50\\x51\\x80\\x81\\x90\\x91\\xC0\\xC1\\xD0\\xD1][\\x20-\\x37][\\x00\\x20\\x40\\x60\\x80\\xA0\\xC0\\xE0])',
931
+ 'group' => 'audio',
932
+ 'module' => 'mpc',
933
+ 'mime_type' => 'audio/x-musepack',
934
+ ),
935
+
936
+ // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
937
+ 'mp3' => array(
938
+ 'pattern' => '^\\xFF[\\xE2-\\xE7\\xF2-\\xF7\\xFA-\\xFF][\\x00-\\x0B\\x10-\\x1B\\x20-\\x2B\\x30-\\x3B\\x40-\\x4B\\x50-\\x5B\\x60-\\x6B\\x70-\\x7B\\x80-\\x8B\\x90-\\x9B\\xA0-\\xAB\\xB0-\\xBB\\xC0-\\xCB\\xD0-\\xDB\\xE0-\\xEB\\xF0-\\xFB]',
939
+ 'group' => 'audio',
940
+ 'module' => 'mp3',
941
+ 'mime_type' => 'audio/mpeg',
942
+ ),
943
+
944
+ // OFR - audio - OptimFROG
945
+ 'ofr' => array(
946
+ 'pattern' => '^(\\*RIFF|OFR)',
947
+ 'group' => 'audio',
948
+ 'module' => 'optimfrog',
949
+ 'mime_type' => 'application/octet-stream',
950
+ ),
951
+
952
+ // RKAU - audio - RKive AUdio compressor
953
+ 'rkau' => array(
954
+ 'pattern' => '^RKA',
955
+ 'group' => 'audio',
956
+ 'module' => 'rkau',
957
+ 'mime_type' => 'application/octet-stream',
958
+ ),
959
+
960
+ // SHN - audio - Shorten
961
+ 'shn' => array(
962
+ 'pattern' => '^ajkg',
963
+ 'group' => 'audio',
964
+ 'module' => 'shorten',
965
+ 'mime_type' => 'audio/xmms-shn',
966
+ 'fail_id3' => 'ERROR',
967
+ 'fail_ape' => 'ERROR',
968
+ ),
969
+
970
+ // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
971
+ 'tta' => array(
972
+ 'pattern' => '^TTA', // could also be '^TTA(\\x01|\\x02|\\x03|2|1)'
973
+ 'group' => 'audio',
974
+ 'module' => 'tta',
975
+ 'mime_type' => 'application/octet-stream',
976
+ ),
977
+
978
+ // VOC - audio - Creative Voice (VOC)
979
+ 'voc' => array(
980
+ 'pattern' => '^Creative Voice File',
981
+ 'group' => 'audio',
982
+ 'module' => 'voc',
983
+ 'mime_type' => 'audio/voc',
984
+ ),
985
+
986
+ // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
987
+ 'vqf' => array(
988
+ 'pattern' => '^TWIN',
989
+ 'group' => 'audio',
990
+ 'module' => 'vqf',
991
+ 'mime_type' => 'application/octet-stream',
992
+ ),
993
+
994
+ // WV - audio - WavPack (v4.0+)
995
+ 'wv' => array(
996
+ 'pattern' => '^wvpk',
997
+ 'group' => 'audio',
998
+ 'module' => 'wavpack',
999
+ 'mime_type' => 'application/octet-stream',
1000
+ ),
1001
+
1002
+
1003
+ // Audio-Video formats
1004
+
1005
+ // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
1006
+ 'asf' => array(
1007
+ 'pattern' => '^\\x30\\x26\\xB2\\x75\\x8E\\x66\\xCF\\x11\\xA6\\xD9\\x00\\xAA\\x00\\x62\\xCE\\x6C',
1008
+ 'group' => 'audio-video',
1009
+ 'module' => 'asf',
1010
+ 'mime_type' => 'video/x-ms-asf',
1011
+ 'iconv_req' => false,
1012
+ ),
1013
+
1014
+ // BINK - audio/video - Bink / Smacker
1015
+ 'bink' => array(
1016
+ 'pattern' => '^(BIK|SMK)',
1017
+ 'group' => 'audio-video',
1018
+ 'module' => 'bink',
1019
+ 'mime_type' => 'application/octet-stream',
1020
+ ),
1021
+
1022
+ // FLV - audio/video - FLash Video
1023
+ 'flv' => array(
1024
+ 'pattern' => '^FLV[\\x01]',
1025
+ 'group' => 'audio-video',
1026
+ 'module' => 'flv',
1027
+ 'mime_type' => 'video/x-flv',
1028
+ ),
1029
+
1030
+ // MKAV - audio/video - Mastroka
1031
+ 'matroska' => array(
1032
+ 'pattern' => '^\\x1A\\x45\\xDF\\xA3',
1033
+ 'group' => 'audio-video',
1034
+ 'module' => 'matroska',
1035
+ 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
1036
+ ),
1037
+
1038
+ // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
1039
+ 'mpeg' => array(
1040
+ 'pattern' => '^\\x00\\x00\\x01[\\xB3\\xBA]',
1041
+ 'group' => 'audio-video',
1042
+ 'module' => 'mpeg',
1043
+ 'mime_type' => 'video/mpeg',
1044
+ ),
1045
+
1046
+ // NSV - audio/video - Nullsoft Streaming Video (NSV)
1047
+ 'nsv' => array(
1048
+ 'pattern' => '^NSV[sf]',
1049
+ 'group' => 'audio-video',
1050
+ 'module' => 'nsv',
1051
+ 'mime_type' => 'application/octet-stream',
1052
+ ),
1053
+
1054
+ // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
1055
+ 'ogg' => array(
1056
+ 'pattern' => '^OggS',
1057
+ 'group' => 'audio',
1058
+ 'module' => 'ogg',
1059
+ 'mime_type' => 'application/ogg',
1060
+ 'fail_id3' => 'WARNING',
1061
+ 'fail_ape' => 'WARNING',
1062
+ ),
1063
+
1064
+ // QT - audio/video - Quicktime
1065
+ 'quicktime' => array(
1066
+ 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
1067
+ 'group' => 'audio-video',
1068
+ 'module' => 'quicktime',
1069
+ 'mime_type' => 'video/quicktime',
1070
+ ),
1071
+
1072
+ // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
1073
+ 'riff' => array(
1074
+ 'pattern' => '^(RIFF|SDSS|FORM)',
1075
+ 'group' => 'audio-video',
1076
+ 'module' => 'riff',
1077
+ 'mime_type' => 'audio/wav',
1078
+ 'fail_ape' => 'WARNING',
1079
+ ),
1080
+
1081
+ // Real - audio/video - RealAudio, RealVideo
1082
+ 'real' => array(
1083
+ 'pattern' => '^\\.(RMF|ra)',
1084
+ 'group' => 'audio-video',
1085
+ 'module' => 'real',
1086
+ 'mime_type' => 'audio/x-realaudio',
1087
+ ),
1088
+
1089
+ // SWF - audio/video - ShockWave Flash
1090
+ 'swf' => array(
1091
+ 'pattern' => '^(F|C)WS',
1092
+ 'group' => 'audio-video',
1093
+ 'module' => 'swf',
1094
+ 'mime_type' => 'application/x-shockwave-flash',
1095
+ ),
1096
+
1097
+ // TS - audio/video - MPEG-2 Transport Stream
1098
+ 'ts' => array(
1099
+ 'pattern' => '^(\\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern
1100
+ 'group' => 'audio-video',
1101
+ 'module' => 'ts',
1102
+ 'mime_type' => 'video/MP2T',
1103
+ ),
1104
+
1105
+
1106
+ // Still-Image formats
1107
+
1108
+ // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
1109
+ 'bmp' => array(
1110
+ 'pattern' => '^BM',
1111
+ 'group' => 'graphic',
1112
+ 'module' => 'bmp',
1113
+ 'mime_type' => 'image/bmp',
1114
+ 'fail_id3' => 'ERROR',
1115
+ 'fail_ape' => 'ERROR',
1116
+ ),
1117
+
1118
+ // GIF - still image - Graphics Interchange Format
1119
+ 'gif' => array(
1120
+ 'pattern' => '^GIF',
1121
+ 'group' => 'graphic',
1122
+ 'module' => 'gif',
1123
+ 'mime_type' => 'image/gif',
1124
+ 'fail_id3' => 'ERROR',
1125
+ 'fail_ape' => 'ERROR',
1126
+ ),
1127
+
1128
+ // JPEG - still image - Joint Photographic Experts Group (JPEG)
1129
+ 'jpg' => array(
1130
+ 'pattern' => '^\\xFF\\xD8\\xFF',
1131
+ 'group' => 'graphic',
1132
+ 'module' => 'jpg',
1133
+ 'mime_type' => 'image/jpeg',
1134
+ 'fail_id3' => 'ERROR',
1135
+ 'fail_ape' => 'ERROR',
1136
+ ),
1137
+
1138
+ // PCD - still image - Kodak Photo CD
1139
+ 'pcd' => array(
1140
+ 'pattern' => '^.{2048}PCD_IPI\\x00',
1141
+ 'group' => 'graphic',
1142
+ 'module' => 'pcd',
1143
+ 'mime_type' => 'image/x-photo-cd',
1144
+ 'fail_id3' => 'ERROR',
1145
+ 'fail_ape' => 'ERROR',
1146
+ ),
1147
+
1148
+
1149
+ // PNG - still image - Portable Network Graphics (PNG)
1150
+ 'png' => array(
1151
+ 'pattern' => '^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A',
1152
+ 'group' => 'graphic',
1153
+ 'module' => 'png',
1154
+ 'mime_type' => 'image/png',
1155
+ 'fail_id3' => 'ERROR',
1156
+ 'fail_ape' => 'ERROR',
1157
+ ),
1158
+
1159
+
1160
+ // SVG - still image - Scalable Vector Graphics (SVG)
1161
+ 'svg' => array(
1162
+ 'pattern' => '(<!DOCTYPE svg PUBLIC |xmlns="http://www\\.w3\\.org/2000/svg")',
1163
+ 'group' => 'graphic',
1164
+ 'module' => 'svg',
1165
+ 'mime_type' => 'image/svg+xml',
1166
+ 'fail_id3' => 'ERROR',
1167
+ 'fail_ape' => 'ERROR',
1168
+ ),
1169
+
1170
+
1171
+ // TIFF - still image - Tagged Information File Format (TIFF)
1172
+ 'tiff' => array(
1173
+ 'pattern' => '^(II\\x2A\\x00|MM\\x00\\x2A)',
1174
+ 'group' => 'graphic',
1175
+ 'module' => 'tiff',
1176
+ 'mime_type' => 'image/tiff',
1177
+ 'fail_id3' => 'ERROR',
1178
+ 'fail_ape' => 'ERROR',
1179
+ ),
1180
+
1181
+
1182
+ // EFAX - still image - eFax (TIFF derivative)
1183
+ 'efax' => array(
1184
+ 'pattern' => '^\\xDC\\xFE',
1185
+ 'group' => 'graphic',
1186
+ 'module' => 'efax',
1187
+ 'mime_type' => 'image/efax',
1188
+ 'fail_id3' => 'ERROR',
1189
+ 'fail_ape' => 'ERROR',
1190
+ ),
1191
+
1192
+
1193
+ // Data formats
1194
+
1195
+ // ISO - data - International Standards Organization (ISO) CD-ROM Image
1196
+ 'iso' => array(
1197
+ 'pattern' => '^.{32769}CD001',
1198
+ 'group' => 'misc',
1199
+ 'module' => 'iso',
1200
+ 'mime_type' => 'application/octet-stream',
1201
+ 'fail_id3' => 'ERROR',
1202
+ 'fail_ape' => 'ERROR',
1203
+ 'iconv_req' => false,
1204
+ ),
1205
+
1206
+ // RAR - data - RAR compressed data
1207
+ 'rar' => array(
1208
+ 'pattern' => '^Rar\\!',
1209
+ 'group' => 'archive',
1210
+ 'module' => 'rar',
1211
+ 'mime_type' => 'application/octet-stream',
1212
+ 'fail_id3' => 'ERROR',
1213
+ 'fail_ape' => 'ERROR',
1214
+ ),
1215
+
1216
+ // SZIP - audio/data - SZIP compressed data
1217
+ 'szip' => array(
1218
+ 'pattern' => '^SZ\\x0A\\x04',
1219
+ 'group' => 'archive',
1220
+ 'module' => 'szip',
1221
+ 'mime_type' => 'application/octet-stream',
1222
+ 'fail_id3' => 'ERROR',
1223
+ 'fail_ape' => 'ERROR',
1224
+ ),
1225
+
1226
+ // TAR - data - TAR compressed data
1227
+ 'tar' => array(
1228
+ 'pattern' => '^.{100}[0-9\\x20]{7}\\x00[0-9\\x20]{7}\\x00[0-9\\x20]{7}\\x00[0-9\\x20\\x00]{12}[0-9\\x20\\x00]{12}',
1229
+ 'group' => 'archive',
1230
+ 'module' => 'tar',
1231
+ 'mime_type' => 'application/x-tar',
1232
+ 'fail_id3' => 'ERROR',
1233
+ 'fail_ape' => 'ERROR',
1234
+ ),
1235
+
1236
+ // GZIP - data - GZIP compressed data
1237
+ 'gz' => array(
1238
+ 'pattern' => '^\\x1F\\x8B\\x08',
1239
+ 'group' => 'archive',
1240
+ 'module' => 'gzip',
1241
+ 'mime_type' => 'application/gzip',
1242
+ 'fail_id3' => 'ERROR',
1243
+ 'fail_ape' => 'ERROR',
1244
+ ),
1245
+
1246
+ // ZIP - data - ZIP compressed data
1247
+ 'zip' => array(
1248
+ 'pattern' => '^PK\\x03\\x04',
1249
+ 'group' => 'archive',
1250
+ 'module' => 'zip',
1251
+ 'mime_type' => 'application/zip',
1252
+ 'fail_id3' => 'ERROR',
1253
+ 'fail_ape' => 'ERROR',
1254
+ ),
1255
+
1256
+ // XZ - data - XZ compressed data
1257
+ 'xz' => array(
1258
+ 'pattern' => '^\\xFD7zXZ\\x00',
1259
+ 'group' => 'archive',
1260
+ 'module' => 'xz',
1261
+ 'mime_type' => 'application/x-xz',
1262
+ 'fail_id3' => 'ERROR',
1263
+ 'fail_ape' => 'ERROR',
1264
+ ),
1265
+
1266
+
1267
+ // Misc other formats
1268
+
1269
+ // PAR2 - data - Parity Volume Set Specification 2.0
1270
+ 'par2' => array (
1271
+ 'pattern' => '^PAR2\\x00PKT',
1272
+ 'group' => 'misc',
1273
+ 'module' => 'par2',
1274
+ 'mime_type' => 'application/octet-stream',
1275
+ 'fail_id3' => 'ERROR',
1276
+ 'fail_ape' => 'ERROR',
1277
+ ),
1278
+
1279
+ // PDF - data - Portable Document Format
1280
+ 'pdf' => array(
1281
+ 'pattern' => '^\\x25PDF',
1282
+ 'group' => 'misc',
1283
+ 'module' => 'pdf',
1284
+ 'mime_type' => 'application/pdf',
1285
+ 'fail_id3' => 'ERROR',
1286
+ 'fail_ape' => 'ERROR',
1287
+ ),
1288
+
1289
+ // MSOFFICE - data - ZIP compressed data
1290
+ 'msoffice' => array(
1291
+ 'pattern' => '^\\xD0\\xCF\\x11\\xE0\\xA1\\xB1\\x1A\\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
1292
+ 'group' => 'misc',
1293
+ 'module' => 'msoffice',
1294
+ 'mime_type' => 'application/octet-stream',
1295
+ 'fail_id3' => 'ERROR',
1296
+ 'fail_ape' => 'ERROR',
1297
+ ),
1298
+
1299
+ // CUE - data - CUEsheet (index to single-file disc images)
1300
+ 'cue' => array(
1301
+ 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
1302
+ 'group' => 'misc',
1303
+ 'module' => 'cue',
1304
+ 'mime_type' => 'application/octet-stream',
1305
+ ),
1306
+
1307
+ );
1308
  }
1309
 
1310
+ return $format_info;
1311
+ }
1312
 
1313
+ /**
1314
+ * @param string $filedata
1315
+ * @param string $filename
1316
+ *
1317
+ * @return mixed|false
1318
+ */
1319
+ public function GetFileFormat(&$filedata, $filename='') {
1320
+ // this function will determine the format of a file based on usually
1321
+ // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
1322
+ // and in the case of ISO CD image, 6 bytes offset 32kb from the start
1323
+ // of the file).
1324
+
1325
+ // Identify file format - loop through $format_info and detect with reg expr
1326
+ foreach ($this->GetFileFormatArray() as $format_name => $info) {
1327
+ // The /s switch on preg_match() forces preg_match() NOT to treat
1328
+ // newline (0x0A) characters as special chars but do a binary match
1329
+ if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) {
 
 
 
 
 
 
1330
  $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1331
  return $info;
 
 
 
 
 
 
 
 
1332
  }
 
 
1333
  }
1334
 
1335
 
1336
+ if (preg_match('#\\.mp[123a]$#i', $filename)) {
1337
+ // Too many mp3 encoders on the market put garbage in front of mpeg files
1338
+ // use assume format on these if format detection failed
1339
+ $GetFileFormatArray = $this->GetFileFormatArray();
1340
+ $info = $GetFileFormatArray['mp3'];
1341
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1342
+ return $info;
1343
+ } elseif (preg_match('#\\.cue$#i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
1344
+ // there's not really a useful consistent "magic" at the beginning of .cue files to identify them
1345
+ // so until I think of something better, just go by filename if all other format checks fail
1346
+ // and verify there's at least one instance of "TRACK xx AUDIO" in the file
1347
+ $GetFileFormatArray = $this->GetFileFormatArray();
1348
+ $info = $GetFileFormatArray['cue'];
1349
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
1350
+ return $info;
1351
+ }
1352
 
1353
+ return false;
1354
+ }
 
 
1355
 
1356
+ /**
1357
+ * Converts array to $encoding charset from $this->encoding.
1358
+ *
1359
+ * @param array $array
1360
+ * @param string $encoding
1361
+ */
1362
+ public function CharConvert(&$array, $encoding) {
1363
+
1364
+ // identical encoding - end here
1365
+ if ($encoding == $this->encoding) {
1366
+ return;
1367
+ }
1368
 
1369
+ // loop thru array
1370
+ foreach ($array as $key => $value) {
 
 
1371
 
1372
+ // go recursive
1373
+ if (is_array($value)) {
1374
+ $this->CharConvert($array[$key], $encoding);
 
1375
  }
 
1376
 
1377
+ // convert string
1378
+ elseif (is_string($value)) {
1379
+ $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1380
  }
1381
+ }
1382
+ }
1383
 
1384
+ /**
1385
+ * @return bool
1386
+ */
1387
+ public function HandleAllTags() {
1388
+
1389
+ // key name => array (tag name, character encoding)
1390
+ static $tags;
1391
+ if (empty($tags)) {
1392
+ $tags = array(
1393
+ 'asf' => array('asf' , 'UTF-16LE'),
1394
+ 'midi' => array('midi' , 'ISO-8859-1'),
1395
+ 'nsv' => array('nsv' , 'ISO-8859-1'),
1396
+ 'ogg' => array('vorbiscomment' , 'UTF-8'),
1397
+ 'png' => array('png' , 'UTF-8'),
1398
+ 'tiff' => array('tiff' , 'ISO-8859-1'),
1399
+ 'quicktime' => array('quicktime' , 'UTF-8'),
1400
+ 'real' => array('real' , 'ISO-8859-1'),
1401
+ 'vqf' => array('vqf' , 'ISO-8859-1'),
1402
+ 'zip' => array('zip' , 'ISO-8859-1'),
1403
+ 'riff' => array('riff' , 'ISO-8859-1'),
1404
+ 'lyrics3' => array('lyrics3' , 'ISO-8859-1'),
1405
+ 'id3v1' => array('id3v1' , $this->encoding_id3v1),
1406
+ 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8
1407
+ 'ape' => array('ape' , 'UTF-8'),
1408
+ 'cue' => array('cue' , 'ISO-8859-1'),
1409
+ 'matroska' => array('matroska' , 'UTF-8'),
1410
+ 'flac' => array('vorbiscomment' , 'UTF-8'),
1411
+ 'divxtag' => array('divx' , 'ISO-8859-1'),
1412
+ 'iptc' => array('iptc' , 'ISO-8859-1'),
1413
+ );
1414
+ }
1415
 
1416
+ // loop through comments array
1417
+ foreach ($tags as $comment_name => $tagname_encoding_array) {
1418
+ list($tag_name, $encoding) = $tagname_encoding_array;
 
1419
 
1420
+ // fill in default encoding type if not already present
1421
+ if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) {
1422
+ $this->info[$comment_name]['encoding'] = $encoding;
1423
+ }
1424
+
1425
+ // copy comments if key name set
1426
+ if (!empty($this->info[$comment_name]['comments'])) {
1427
+ foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
1428
+ foreach ($valuearray as $key => $value) {
1429
+ if (is_string($value)) {
1430
+ $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
 
 
 
1431
  }
1432
+ if ($value) {
1433
+ if (!is_numeric($key)) {
1434
+ $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
1435
+ } else {
1436
+ $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
1437
+ }
1438
  }
1439
  }
1440
+ if ($tag_key == 'picture') {
1441
+ // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
1442
+ unset($this->info[$comment_name]['comments'][$tag_key]);
 
1443
  }
1444
+ }
1445
 
1446
+ if (!isset($this->info['tags'][$tag_name])) {
1447
+ // comments are set but contain nothing but empty strings, so skip
1448
+ continue;
1449
+ }
 
1450
 
1451
+ $this->CharConvert($this->info['tags'][$tag_name], $this->info[$comment_name]['encoding']); // only copy gets converted!
1452
+
1453
+ if ($this->option_tags_html) {
1454
+ foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
1455
+ if ($tag_key == 'picture') {
1456
+ // Do not to try to convert binary picture data to HTML
1457
+ // https://github.com/JamesHeinrich/getID3/issues/178
1458
+ continue;
 
 
 
 
 
 
 
 
 
 
 
1459
  }
1460
+ $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
1461
  }
 
 
 
1462
  }
1463
 
1464
  }
1465
 
1466
+ }
1467
+
1468
+ // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
1469
+ if (!empty($this->info['tags'])) {
1470
+ $unset_keys = array('tags', 'tags_html');
1471
+ foreach ($this->info['tags'] as $tagtype => $tagarray) {
1472
+ foreach ($tagarray as $tagname => $tagdata) {
1473
+ if ($tagname == 'picture') {
1474
+ foreach ($tagdata as $key => $tagarray) {
1475
+ $this->info['comments']['picture'][] = $tagarray;
1476
+ if (isset($tagarray['data']) && isset($tagarray['image_mime'])) {
1477
+ if (isset($this->info['tags'][$tagtype][$tagname][$key])) {
1478
+ unset($this->info['tags'][$tagtype][$tagname][$key]);
1479
+ }
1480
+ if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) {
1481
+ unset($this->info['tags_html'][$tagtype][$tagname][$key]);
1482
  }
1483
  }
1484
  }
1485
  }
1486
+ }
1487
+ foreach ($unset_keys as $unset_key) {
1488
+ // remove possible empty keys from (e.g. [tags][id3v2][picture])
1489
+ if (empty($this->info[$unset_key][$tagtype]['picture'])) {
1490
+ unset($this->info[$unset_key][$tagtype]['picture']);
 
 
 
 
 
 
 
 
 
 
1491
  }
1492
+ if (empty($this->info[$unset_key][$tagtype])) {
1493
+ unset($this->info[$unset_key][$tagtype]);
1494
  }
1495
+ if (empty($this->info[$unset_key])) {
1496
+ unset($this->info[$unset_key]);
1497
  }
1498
  }
1499
+ // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture])
1500
+ if (isset($this->info[$tagtype]['comments']['picture'])) {
1501
+ unset($this->info[$tagtype]['comments']['picture']);
1502
+ }
1503
+ if (empty($this->info[$tagtype]['comments'])) {
1504
+ unset($this->info[$tagtype]['comments']);
1505
+ }
1506
+ if (empty($this->info[$tagtype])) {
1507
+ unset($this->info[$tagtype]);
1508
+ }
1509
  }
 
1510
  }
1511
+ return true;
1512
+ }
1513
 
1514
+ /**
1515
+ * @param string $algorithm
1516
+ *
1517
+ * @return array|bool
1518
+ */
1519
+ public function getHashdata($algorithm) {
1520
+ switch ($algorithm) {
1521
+ case 'md5':
1522
+ case 'sha1':
1523
+ break;
1524
+
1525
+ default:
1526
+ return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
1527
+ break;
1528
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1529
 
1530
+ if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
1531
+
1532
+ // We cannot get an identical md5_data value for Ogg files where the comments
1533
+ // span more than 1 Ogg page (compared to the same audio data with smaller
1534
+ // comments) using the normal getID3() method of MD5'ing the data between the
1535
+ // end of the comments and the end of the file (minus any trailing tags),
1536
+ // because the page sequence numbers of the pages that the audio data is on
1537
+ // do not match. Under normal circumstances, where comments are smaller than
1538
+ // the nominal 4-8kB page size, then this is not a problem, but if there are
1539
+ // very large comments, the only way around it is to strip off the comment
1540
+ // tags with vorbiscomment and MD5 that file.
1541
+ // This procedure must be applied to ALL Ogg files, not just the ones with
1542
+ // comments larger than 1 page, because the below method simply MD5's the
1543
+ // whole file with the comments stripped, not just the portion after the
1544
+ // comments block (which is the standard getID3() method.
1545
+
1546
+ // The above-mentioned problem of comments spanning multiple pages and changing
1547
+ // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
1548
+ // currently vorbiscomment only works on OggVorbis files.
1549
 
1550
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
 
 
1551
 
1552
+ $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
1553
+ $this->info[$algorithm.'_data'] = false;
1554
 
1555
+ } else {
1556
 
1557
+ // Prevent user from aborting script
1558
+ $old_abort = ignore_user_abort(true);
1559
 
1560
+ // Create empty file
1561
+ $empty = tempnam(GETID3_TEMP_DIR, 'getID3');
1562
+ touch($empty);
1563
 
1564
+ // Use vorbiscomment to make temp file without comments
1565
+ $temp = tempnam(GETID3_TEMP_DIR, 'getID3');
1566
+ $file = $this->info['filenamepath'];
1567
 
1568
+ if (GETID3_OS_ISWINDOWS) {
1569
 
1570
+ if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
1571
 
1572
+ $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"';
 
1573
  $VorbisCommentError = `$commandline`;
1574
 
 
 
 
 
 
 
 
1575
  } else {
1576
 
1577
+ $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
 
 
 
 
1578
 
 
 
 
 
1579
  }
1580
 
1581
+ } else {
 
 
1582
 
1583
+ $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
1584
+ $VorbisCommentError = `$commandline`;
1585
 
1586
  }
1587
 
1588
+ if (!empty($VorbisCommentError)) {
 
 
1589
 
1590
+ $this->warning('Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError);
1591
+ $this->info[$algorithm.'_data'] = false;
1592
 
1593
  } else {
1594
 
1595
+ // Get hash of newly created file
1596
  switch ($algorithm) {
1597
  case 'md5':
1598
+ $this->info[$algorithm.'_data'] = md5_file($temp);
1599
  break;
1600
 
1601
  case 'sha1':
1602
+ $this->info[$algorithm.'_data'] = sha1_file($temp);
1603
  break;
1604
  }
1605
  }
1606
 
1607
+ // Clean up
1608
+ unlink($empty);
1609
+ unlink($temp);
1610
+
1611
+ // Reset abort setting
1612
+ ignore_user_abort($old_abort);
1613
+
1614
  }
 
 
1615
 
1616
+ } else {
1617
 
1618
+ if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) {
1619
 
1620
+ // get hash from part of file
1621
+ $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
 
 
 
 
 
 
1622
 
1623
+ } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1624
 
1625
+ // get hash from whole file
1626
+ switch ($algorithm) {
1627
+ case 'md5':
1628
+ $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']);
1629
+ break;
1630
 
1631
+ case 'sha1':
1632
+ $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']);
1633
+ break;
 
 
 
 
 
 
 
1634
  }
1635
  }
1636
 
 
 
 
 
1637
  }
1638
+ return true;
1639
+ }
1640
 
1641
+ public function ChannelsBitratePlaytimeCalculations() {
1642
 
1643
+ // set channelmode on audio
1644
+ if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
1645
+ // ignore
1646
+ } elseif ($this->info['audio']['channels'] == 1) {
1647
+ $this->info['audio']['channelmode'] = 'mono';
1648
+ } elseif ($this->info['audio']['channels'] == 2) {
1649
+ $this->info['audio']['channelmode'] = 'stereo';
1650
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1651
 
1652
+ // Calculate combined bitrate - audio + video
1653
+ $CombinedBitrate = 0;
1654
+ $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
1655
+ $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
1656
+ if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) {
1657
+ $this->info['bitrate'] = $CombinedBitrate;
1658
+ }
1659
+ //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
1660
+ // // for example, VBR MPEG video files cannot determine video bitrate:
1661
+ // // should not set overall bitrate and playtime from audio bitrate only
1662
+ // unset($this->info['bitrate']);
1663
+ //}
1664
+
1665
+ // video bitrate undetermined, but calculable
1666
+ if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) {
1667
+ // if video bitrate not set
1668
+ if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) {
1669
+ // AND if audio bitrate is set to same as overall bitrate
1670
+ if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) {
1671
+ // AND if playtime is set
1672
+ if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) {
1673
+ // AND if AV data offset start/end is known
1674
+ // THEN we can calculate the video bitrate
1675
+ $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']);
1676
+ $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate'];
1677
  }
1678
+ }
1679
  }
 
 
 
 
1680
  }
1681
 
1682
+ if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
1683
+ $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
1684
+ }
1685
 
1686
+ if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
1687
+ $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
1688
+ }
1689
+ if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
1690
+ if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
1691
+ // audio only
1692
+ $this->info['audio']['bitrate'] = $this->info['bitrate'];
1693
+ } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
1694
+ // video only
1695
+ $this->info['video']['bitrate'] = $this->info['bitrate'];
1696
  }
1697
+ }
1698
 
1699
+ // Set playtime string
1700
+ if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
1701
+ $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
 
 
 
 
 
1702
  }
1703
+ }
1704
 
1705
+ /**
1706
+ * @return bool
1707
+ */
1708
+ public function CalculateCompressionRatioVideo() {
1709
+ if (empty($this->info['video'])) {
1710
+ return false;
1711
+ }
1712
+ if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
1713
+ return false;
1714
+ }
1715
+ if (empty($this->info['video']['bits_per_sample'])) {
1716
+ return false;
1717
+ }
1718
 
1719
+ switch ($this->info['video']['dataformat']) {
1720
+ case 'bmp':
1721
+ case 'gif':
1722
+ case 'jpeg':
1723
+ case 'jpg':
1724
+ case 'png':
1725
+ case 'tiff':
1726
+ $FrameRate = 1;
1727
+ $PlaytimeSeconds = 1;
1728
+ $BitrateCompressed = $this->info['filesize'] * 8;
1729
+ break;
1730
+
1731
+ default:
1732
+ if (!empty($this->info['video']['frame_rate'])) {
1733
+ $FrameRate = $this->info['video']['frame_rate'];
1734
+ } else {
1735
+ return false;
1736
  }
1737
+ if (!empty($this->info['playtime_seconds'])) {
1738
+ $PlaytimeSeconds = $this->info['playtime_seconds'];
1739
+ } else {
1740
+ return false;
1741
  }
1742
+ if (!empty($this->info['video']['bitrate'])) {
1743
+ $BitrateCompressed = $this->info['video']['bitrate'];
1744
+ } else {
1745
+ return false;
1746
  }
1747
+ break;
1748
+ }
1749
+ $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;
1750
 
1751
+ $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
1752
+ return true;
1753
+ }
1754
+
1755
+ /**
1756
+ * @return bool
1757
+ */
1758
+ public function CalculateCompressionRatioAudio() {
1759
+ if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
1760
+ return false;
1761
  }
1762
+ $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
1763
 
1764
+ if (!empty($this->info['audio']['streams'])) {
1765
+ foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
1766
+ if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
1767
+ $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
 
 
 
 
1768
  }
1769
  }
 
1770
  }
1771
+ return true;
1772
+ }
1773
 
1774
+ /**
1775
+ * @return bool
1776
+ */
1777
+ public function CalculateReplayGain() {
1778
+ if (isset($this->info['replay_gain'])) {
1779
+ if (!isset($this->info['replay_gain']['reference_volume'])) {
1780
+ $this->info['replay_gain']['reference_volume'] = 89.0;
1781
+ }
1782
+ if (isset($this->info['replay_gain']['track']['adjustment'])) {
1783
+ $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
1784
+ }
1785
+ if (isset($this->info['replay_gain']['album']['adjustment'])) {
1786
+ $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
1787
+ }
1788
 
1789
+ if (isset($this->info['replay_gain']['track']['peak'])) {
1790
+ $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
1791
+ }
1792
+ if (isset($this->info['replay_gain']['album']['peak'])) {
1793
+ $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
1794
  }
 
 
1795
  }
1796
+ return true;
1797
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1798
 
1799
+ /**
1800
+ * @return bool
1801
+ */
1802
+ public function ProcessAudioStreams() {
1803
+ if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
1804
+ if (!isset($this->info['audio']['streams'])) {
1805
+ foreach ($this->info['audio'] as $key => $value) {
1806
+ if ($key != 'streams') {
1807
+ $this->info['audio']['streams'][0][$key] = $value;
1808
+ }
1809
+ }
1810
  }
1811
  }
1812
+ return true;
1813
+ }
1814
 
1815
+ /**
1816
+ * @return string|bool
1817
+ */
1818
+ public function getid3_tempnam() {
1819
+ return tempnam($this->tempdir, 'gI3');
1820
+ }
1821
 
1822
+ /**
1823
+ * @param string $name
1824
+ *
1825
+ * @return bool
1826
+ *
1827
+ * @throws getid3_exception
1828
+ */
1829
+ public function include_module($name) {
1830
+ //if (!file_exists($this->include_path.'module.'.$name.'.php')) {
1831
+ if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
1832
+ throw new getid3_exception('Required module.'.$name.'.php is missing.');
1833
+ }
1834
+ include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
1835
+ return true;
1836
+ }
1837
 
1838
+ /**
1839
+ * @param string $filename
1840
+ *
1841
+ * @return bool
1842
+ */
1843
+ public static function is_writable ($filename) {
1844
+ $ret = is_writable($filename);
1845
+ if (!$ret) {
1846
+ $perms = fileperms($filename);
1847
+ $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
1848
+ }
1849
+ return $ret;
1850
+ }
1851
 
1852
+ }
 
 
 
1853
 
 
 
 
 
1854
 
1855
+ abstract class getid3_handler
1856
+ {
1857
+
1858
+ /**
1859
+ * @var getID3
1860
+ */
1861
+ protected $getid3; // pointer
1862
+
1863
+ /**
1864
+ * Analyzing filepointer or string.
1865
+ *
1866
+ * @var bool
1867
+ */
1868
+ protected $data_string_flag = false;
1869
+
1870
+ /**
1871
+ * String to analyze.
1872
+ *
1873
+ * @var string
1874
+ */
1875
+ protected $data_string = '';
1876
+
1877
+ /**
1878
+ * Seek position in string.
1879
+ *
1880
+ * @var int
1881
+ */
1882
+ protected $data_string_position = 0;
1883
+
1884
+ /**
1885
+ * String length.
1886
+ *
1887
+ * @var int
1888
+ */
1889
+ protected $data_string_length = 0;
1890
+
1891
+ /**
1892
+ * @var string
1893
+ */
1894
+ private $dependency_to;
1895
+
1896
+ /**
1897
+ * getid3_handler constructor.
1898
+ *
1899
+ * @param getID3 $getid3
1900
+ * @param string $call_module
1901
+ */
1902
+ public function __construct(getID3 $getid3, $call_module=null) {
1903
+ $this->getid3 = $getid3;
1904
+
1905
+ if ($call_module) {
1906
+ $this->dependency_to = str_replace('getid3_', '', $call_module);
1907
+ }
1908
+ }
1909
 
1910
+ /**
1911
+ * Analyze from file pointer.
1912
+ *
1913
+ * @return bool
1914
+ */
1915
+ abstract public function Analyze();
1916
+
1917
+ /**
1918
+ * Analyze from string instead.
1919
+ *
1920
+ * @param string $string
1921
+ */
1922
+ public function AnalyzeString($string) {
1923
+ // Enter string mode
1924
+ $this->setStringMode($string);
1925
+
1926
+ // Save info
1927
+ $saved_avdataoffset = $this->getid3->info['avdataoffset'];
1928
+ $saved_avdataend = $this->getid3->info['avdataend'];
1929
+ $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call
1930
+
1931
+ // Reset some info
1932
+ $this->getid3->info['avdataoffset'] = 0;
1933
+ $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length;
1934
+
1935
+ // Analyze
1936
+ $this->Analyze();
1937
+
1938
+ // Restore some info
1939
+ $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
1940
+ $this->getid3->info['avdataend'] = $saved_avdataend;
1941
+ $this->getid3->info['filesize'] = $saved_filesize;
1942
+
1943
+ // Exit string mode
1944
+ $this->data_string_flag = false;
1945
+ }
1946
 
1947
+ /**
1948
+ * @param string $string
1949
+ */
1950
+ public function setStringMode($string) {
1951
+ $this->data_string_flag = true;
1952
+ $this->data_string = $string;
1953
+ $this->data_string_length = strlen($string);
1954
+ }
1955
 
1956
+ /**
1957
+ * @return int|bool
1958
+ */
1959
+ protected function ftell() {
1960
+ if ($this->data_string_flag) {
1961
+ return $this->data_string_position;
1962
  }
1963
+ return ftell($this->getid3->fp);
1964
+ }
1965
 
1966
+ /**
1967
+ * @param int $bytes
1968
+ *
1969
+ * @return string|false
1970
+ *
1971
+ * @throws getid3_exception
1972
+ */
1973
+ protected function fread($bytes) {
1974
+ if ($this->data_string_flag) {
1975
+ $this->data_string_position += $bytes;
1976
+ return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
1977
  }
1978
+ $pos = $this->ftell() + $bytes;
1979
+ if (!getid3_lib::intValueSupported($pos)) {
1980
+ throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
 
 
 
1981
  }
1982
 
1983
+ //return fread($this->getid3->fp, $bytes);
1984
+ /*
1985
+ * https://www.getid3.org/phpBB3/viewtopic.php?t=1930
1986
+ * "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
1987
+ * It seems to assume that fread() would always return as many bytes as were requested.
1988
+ * However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes.
1989
+ * The call may return only part of the requested data and a new call is needed to get more."
1990
+ */
1991
+ $contents = '';
1992
+ do {
1993
+ //if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
1994
+ if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)"
1995
+ throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
1996
  }
1997
+ $part = fread($this->getid3->fp, $bytes);
1998
+ $partLength = strlen($part);
1999
+ $bytes -= $partLength;
2000
+ $contents .= $part;
2001
+ } while (($bytes > 0) && ($partLength > 0));
2002
+ return $contents;
2003
+ }
2004
 
2005
+ /**
2006
+ * @param int $bytes
2007
+ * @param int $whence
2008
+ *
2009
+ * @return int
2010
+ *
2011
+ * @throws getid3_exception
2012
+ */
2013
+ protected function fseek($bytes, $whence=SEEK_SET) {
2014
+ if ($this->data_string_flag) {
2015
+ switch ($whence) {
2016
+ case SEEK_SET:
2017
+ $this->data_string_position = $bytes;
2018
+ break;
2019
 
2020
+ case SEEK_CUR:
2021
+ $this->data_string_position += $bytes;
2022
+ break;
2023
 
2024
+ case SEEK_END:
2025
+ $this->data_string_position = $this->data_string_length + $bytes;
2026
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
2027
  }
2028
+ return 0;
2029
+ } else {
2030
+ $pos = $bytes;
2031
+ if ($whence == SEEK_CUR) {
2032
+ $pos = $this->ftell() + $bytes;
2033
+ } elseif ($whence == SEEK_END) {
2034
+ $pos = $this->getid3->info['filesize'] + $bytes;
2035
+ }
2036
+ if (!getid3_lib::intValueSupported($pos)) {
2037
+ throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
2038
  }
 
 
 
 
 
 
 
 
 
 
 
2039
  }
2040
+ return fseek($this->getid3->fp, $bytes, $whence);
2041
+ }
2042
 
2043
+ /**
2044
+ * @return bool
2045
+ */
2046
+ protected function feof() {
2047
+ if ($this->data_string_flag) {
2048
+ return $this->data_string_position >= $this->data_string_length;
2049
  }
2050
+ return feof($this->getid3->fp);
2051
+ }
2052
 
2053
+ /**
2054
+ * @param string $module
2055
+ *
2056
+ * @return bool
2057
+ */
2058
+ final protected function isDependencyFor($module) {
2059
+ return $this->dependency_to == $module;
2060
+ }
2061
 
2062
+ /**
2063
+ * @param string $text
2064
+ *
2065
+ * @return bool
2066
+ */
2067
+ protected function error($text) {
2068
+ $this->getid3->info['error'][] = $text;
2069
 
2070
+ return false;
2071
+ }
2072
 
2073
+ /**
2074
+ * @param string $text
2075
+ *
2076
+ * @return bool
2077
+ */
2078
+ protected function warning($text) {
2079
+ return $this->getid3->warning($text);
2080
+ }
2081
 
2082
+ /**
2083
+ * @param string $text
2084
+ */
2085
+ protected function notice($text) {
2086
+ // does nothing for now
2087
+ }
2088
 
2089
+ /**
2090
+ * @param string $name
2091
+ * @param int $offset
2092
+ * @param int $length
2093
+ * @param string $image_mime
2094
+ *
2095
+ * @return string|null
2096
+ *
2097
+ * @throws Exception
2098
+ * @throws getid3_exception
2099
+ */
2100
+ public function saveAttachment($name, $offset, $length, $image_mime=null) {
2101
+ try {
2102
+
2103
+ // do not extract at all
2104
+ if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
2105
+
2106
+ $attachment = null; // do not set any
2107
+
2108
+ // extract to return array
2109
+ } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
2110
+
2111
+ $this->fseek($offset);
2112
+ $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory
2113
+ if ($attachment === false || strlen($attachment) != $length) {
2114
+ throw new Exception('failed to read attachment data');
2115
+ }
2116
 
2117
+ // assume directory path is given
2118
+ } else {
2119
 
2120
+ // set up destination path
2121
+ $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
2122
+ if (!is_dir($dir) || !getID3::is_writable($dir)) { // check supplied directory
2123
+ throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
2124
+ }
2125
+ $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
2126
 
2127
+ // create dest file
2128
+ if (($fp_dest = fopen($dest, 'wb')) == false) {
2129
+ throw new Exception('failed to create file '.$dest);
2130
+ }
2131
 
2132
+ // copy data
2133
+ $this->fseek($offset);
2134
+ $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
2135
+ $bytesleft = $length;
2136
+ while ($bytesleft > 0) {
2137
+ if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) {
2138
+ throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
 
 
2139
  }
2140
+ $bytesleft -= $byteswritten;
 
 
 
2141
  }
2142
 
2143
+ fclose($fp_dest);
2144
+ $attachment = $dest;
2145
 
2146
+ }
 
 
 
 
2147
 
2148
+ } catch (Exception $e) {
 
 
2149
 
2150
+ // close and remove dest file if created
2151
+ if (isset($fp_dest) && is_resource($fp_dest)) {
2152
+ fclose($fp_dest);
2153
  }
2154
 
2155
+ if (isset($dest) && file_exists($dest)) {
2156
+ unlink($dest);
2157
+ }
2158
+
2159
+ // do not set any is case of error
2160
+ $attachment = null;
2161
+ $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage());
2162
 
 
2163
  }
2164
 
2165
+ // seek to the end of attachment
2166
+ $this->fseek($offset + $length);
2167
+
2168
+ return $attachment;
2169
  }
2170
+
2171
  }
2172
 
2173
 
2174
+ class getid3_exception extends Exception
2175
+ {
2176
+ public $message;
 
 
2177
  }
lib/getid3/module.archive.gzip.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.gzip.php //
@@ -20,11 +20,20 @@
20
  /////////////////////////////////////////////////////////////////
21
 
22
 
23
- class getid3_gzip extends getid3_handler {
24
-
25
- // public: Optional file list - disable for speed.
26
- public $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
 
 
 
 
 
 
27
 
 
 
 
28
  public function Analyze() {
29
  $info = &$this->getid3->info;
30
 
@@ -37,13 +46,14 @@ class getid3_gzip extends getid3_handler {
37
  //+---+---+---+---+---+---+---+---+---+---+
38
 
39
  if ($info['php_memory_limit'] && ($info['filesize'] > $info['php_memory_limit'])) {
40
- $info['error'][] = 'File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)';
41
  return false;
42
  }
43
  $this->fseek(0);
44
  $buffer = $this->fread($info['filesize']);
45
 
46
  $arr_members = explode("\x1F\x8B\x08", $buffer);
 
47
  while (true) {
48
  $is_wrong_members = false;
49
  $num_members = intval(count($arr_members));
@@ -97,7 +107,7 @@ class getid3_gzip extends getid3_handler {
97
 
98
  $thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']);
99
  if (!$thisInfo['os']) {
100
- $info['error'][] = 'Read error on gzip file';
101
  return false;
102
  }
103
 
@@ -199,7 +209,7 @@ class getid3_gzip extends getid3_handler {
199
  $inflated = gzinflate($cdata);
200
 
201
  // Calculate CRC32 for inflated content
202
- $thisInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisInfo['crc32']);
203
 
204
  // determine format
205
  $formattest = substr($inflated, 0, 32774);
@@ -215,7 +225,7 @@ class getid3_gzip extends getid3_handler {
215
  if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && include_once(GETID3_INCLUDEPATH.$determined_format['include'])) {
216
  if (($temp_tar_filename = tempnam(GETID3_TEMP_DIR, 'getID3')) === false) {
217
  // can't find anywhere to create a temp file, abort
218
- $info['error'][] = 'Unable to create temp file to parse TAR inside GZIP file';
219
  break;
220
  }
221
  if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
@@ -229,7 +239,7 @@ class getid3_gzip extends getid3_handler {
229
  unset($getid3_temp, $getid3_tar);
230
  unlink($temp_tar_filename);
231
  } else {
232
- $info['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
233
  break;
234
  }
235
  }
@@ -240,13 +250,21 @@ class getid3_gzip extends getid3_handler {
240
  // unknown or unhandled format
241
  break;
242
  }
 
 
243
  }
244
  }
245
  }
246
  return true;
247
  }
248
 
249
- // Converts the OS type
 
 
 
 
 
 
250
  public function get_os_type($key) {
251
  static $os_type = array(
252
  '0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
@@ -268,7 +286,13 @@ class getid3_gzip extends getid3_handler {
268
  return (isset($os_type[$key]) ? $os_type[$key] : '');
269
  }
270
 
271
- // Converts the eXtra FLags
 
 
 
 
 
 
272
  public function get_xflag_type($key) {
273
  static $xflag_type = array(
274
  '0' => 'unknown',
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.gzip.php //
20
  /////////////////////////////////////////////////////////////////
21
 
22
 
23
+ class getid3_gzip extends getid3_handler
24
+ {
25
+ /**
26
+ * Optional file list - disable for speed.
27
+ *
28
+ * Decode gzipped files, if possible, and parse recursively (.tar.gz for example).
29
+ *
30
+ * @var bool
31
+ */
32
+ public $option_gzip_parse_contents = false;
33
 
34
+ /**
35
+ * @return bool
36
+ */
37
  public function Analyze() {
38
  $info = &$this->getid3->info;
39
 
46
  //+---+---+---+---+---+---+---+---+---+---+
47
 
48
  if ($info['php_memory_limit'] && ($info['filesize'] > $info['php_memory_limit'])) {
49
+ $this->error('File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)');
50
  return false;
51
  }
52
  $this->fseek(0);
53
  $buffer = $this->fread($info['filesize']);
54
 
55
  $arr_members = explode("\x1F\x8B\x08", $buffer);
56
+ $num_members = 0;
57
  while (true) {
58
  $is_wrong_members = false;
59
  $num_members = intval(count($arr_members));
107
 
108
  $thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']);
109
  if (!$thisInfo['os']) {
110
+ $this->error('Read error on gzip file');
111
  return false;
112
  }
113
 
209
  $inflated = gzinflate($cdata);
210
 
211
  // Calculate CRC32 for inflated content
212
+ $thisInfo['crc32_valid'] = sprintf('%u', crc32($inflated)) == $thisInfo['crc32'];
213
 
214
  // determine format
215
  $formattest = substr($inflated, 0, 32774);
225
  if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && include_once(GETID3_INCLUDEPATH.$determined_format['include'])) {
226
  if (($temp_tar_filename = tempnam(GETID3_TEMP_DIR, 'getID3')) === false) {
227
  // can't find anywhere to create a temp file, abort
228
+ $this->error('Unable to create temp file to parse TAR inside GZIP file');
229
  break;
230
  }
231
  if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
239
  unset($getid3_temp, $getid3_tar);
240
  unlink($temp_tar_filename);
241
  } else {
242
+ $this->error('Unable to fopen() temp file to parse TAR inside GZIP file');
243
  break;
244
  }
245
  }
250
  // unknown or unhandled format
251
  break;
252
  }
253
+ } else {
254
+ $this->warning('PHP is not compiled with gzinflate() support. Please enable PHP Zlib extension or recompile with the --with-zlib switch');
255
  }
256
  }
257
  }
258
  return true;
259
  }
260
 
261
+ /**
262
+ * Converts the OS type.
263
+ *
264
+ * @param string $key
265
+ *
266
+ * @return string
267
+ */
268
  public function get_os_type($key) {
269
  static $os_type = array(
270
  '0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
286
  return (isset($os_type[$key]) ? $os_type[$key] : '');
287
  }
288
 
289
+ /**
290
+ * Converts the eXtra FLags.
291
+ *
292
+ * @param string $key
293
+ *
294
+ * @return string
295
+ */
296
  public function get_xflag_type($key) {
297
  static $xflag_type = array(
298
  '0' => 'unknown',
lib/getid3/module.archive.rar.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.rar.php //
@@ -17,9 +17,14 @@
17
 
18
  class getid3_rar extends getid3_handler
19
  {
20
-
 
 
21
  public $option_use_rar_extension = false;
22
 
 
 
 
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
@@ -36,13 +41,13 @@ class getid3_rar extends getid3_handler
36
  rar_close($rp);
37
  return true;
38
  } else {
39
- $info['error'][] = 'failed to rar_open('.$info['filename'].')';
40
  }
41
  } else {
42
- $info['error'][] = 'RAR support does not appear to be available in this PHP installation';
43
  }
44
  } else {
45
- $info['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)';
46
  }
47
  return false;
48
 
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.rar.php //
17
 
18
  class getid3_rar extends getid3_handler
19
  {
20
+ /**
21
+ * @var bool
22
+ */
23
  public $option_use_rar_extension = false;
24
 
25
+ /**
26
+ * @return bool
27
+ */
28
  public function Analyze() {
29
  $info = &$this->getid3->info;
30
 
41
  rar_close($rp);
42
  return true;
43
  } else {
44
+ $this->error('failed to rar_open('.$info['filename'].')');
45
  }
46
  } else {
47
+ $this->error('RAR support does not appear to be available in this PHP installation');
48
  }
49
  } else {
50
+ $this->error('PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)');
51
  }
52
  return false;
53
 
lib/getid3/module.archive.szip.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.szip.php //
@@ -17,21 +17,23 @@
17
 
18
  class getid3_szip extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
24
  $this->fseek($info['avdataoffset']);
25
  $SZIPHeader = $this->fread(6);
26
  if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") {
27
- $info['error'][] = 'Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"';
28
  return false;
29
  }
30
  $info['fileformat'] = 'szip';
31
  $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
32
  $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
33
- $info['error'][] = 'SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
34
- return false;
35
 
36
  while (!$this->feof()) {
37
  $NextBlockID = $this->fread(2);
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.szip.php //
17
 
18
  class getid3_szip extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
26
  $this->fseek($info['avdataoffset']);
27
  $SZIPHeader = $this->fread(6);
28
  if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") {
29
+ $this->error('Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"');
30
  return false;
31
  }
32
  $info['fileformat'] = 'szip';
33
  $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
34
  $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
35
+ $this->error('SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
36
+ return false;
37
 
38
  while (!$this->feof()) {
39
  $NextBlockID = $this->fread(2);
lib/getid3/module.archive.tar.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.tar.php //
@@ -22,7 +22,9 @@
22
 
23
  class getid3_tar extends getid3_handler
24
  {
25
-
 
 
26
  public function Analyze() {
27
  $info = &$this->getid3->info;
28
 
@@ -117,7 +119,13 @@ class getid3_tar extends getid3_handler
117
  return true;
118
  }
119
 
120
- // Parses the file mode to file permissions
 
 
 
 
 
 
121
  public function display_perms($mode) {
122
  // Determine Type
123
  if ($mode & 0x1000) $type='p'; // FIFO pipe
@@ -152,7 +160,13 @@ class getid3_tar extends getid3_handler
152
  return $s;
153
  }
154
 
155
- // Converts the file type
 
 
 
 
 
 
156
  public function get_flag_type($typflag) {
157
  static $flag_types = array(
158
  '0' => 'LF_NORMAL',
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.tar.php //
22
 
23
  class getid3_tar extends getid3_handler
24
  {
25
+ /**
26
+ * @return bool
27
+ */
28
  public function Analyze() {
29
  $info = &$this->getid3->info;
30
 
119
  return true;
120
  }
121
 
122
+ /**
123
+ * Parses the file mode to file permissions.
124
+ *
125
+ * @param int $mode
126
+ *
127
+ * @return string
128
+ */
129
  public function display_perms($mode) {
130
  // Determine Type
131
  if ($mode & 0x1000) $type='p'; // FIFO pipe
160
  return $s;
161
  }
162
 
163
+ /**
164
+ * Converts the file type.
165
+ *
166
+ * @param string $typflag
167
+ *
168
+ * @return mixed|string
169
+ */
170
  public function get_flag_type($typflag) {
171
  static $flag_types = array(
172
  '0' => 'LF_NORMAL',
lib/getid3/module.archive.xz.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /////////////////////////////////////////////////////////////////
4
+ /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
9
+ /////////////////////////////////////////////////////////////////
10
+ // //
11
+ // module.archive.xz.php //
12
+ // module for analyzing XZ files //
13
+ // dependencies: NONE //
14
+ // ///
15
+ /////////////////////////////////////////////////////////////////
16
+
17
+
18
+ class getid3_xz extends getid3_handler
19
+ {
20
+
21
+ /**
22
+ * @return bool
23
+ */
24
+ public function Analyze() {
25
+ $info = &$this->getid3->info;
26
+
27
+ $this->fseek($info['avdataoffset']);
28
+ $xzheader = $this->fread(6);
29
+
30
+ // https://tukaani.org/xz/xz-file-format-1.0.4.txt
31
+ $info['xz']['stream_header']['magic'] = substr($xzheader, 0, 6);
32
+ if ($info['xz']['stream_header']['magic'] != "\xFD".'7zXZ'."\x00") {
33
+ $this->error('Invalid XZ stream header magic (expecting FD 37 7A 58 5A 00, found '.getid3_lib::PrintHexBytes($info['xz']['stream_header']['magic']).') at offset '.$info['avdataoffset']);
34
+ return false;
35
+ }
36
+ $info['fileformat'] = 'xz';
37
+ $this->error('XZ parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
38
+ return false;
39
+
40
+ }
41
+
42
+ }
lib/getid3/module.archive.zip.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.zip.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_zip extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -30,7 +32,7 @@ class getid3_zip extends getid3_handler
30
  $info['zip']['entries_count'] = 0;
31
 
32
  if (!getid3_lib::intValueSupported($info['filesize'])) {
33
- $info['error'][] = 'File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP';
34
  return false;
35
  } else {
36
  $EOCDsearchData = '';
@@ -48,7 +50,7 @@ class getid3_zip extends getid3_handler
48
 
49
  $this->fseek($info['zip']['end_central_directory']['directory_offset']);
50
  $info['zip']['entries_count'] = 0;
51
- while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
52
  $info['zip']['central_directory'][] = $centraldirectoryentry;
53
  $info['zip']['entries_count']++;
54
  $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
@@ -61,7 +63,7 @@ class getid3_zip extends getid3_handler
61
  }
62
 
63
  if ($info['zip']['entries_count'] == 0) {
64
- $info['error'][] = 'No Central Directory entries found (truncated file?)';
65
  return false;
66
  }
67
 
@@ -86,7 +88,7 @@ class getid3_zip extends getid3_handler
86
  if ($fileentry = $this->ZIPparseLocalFileHeader()) {
87
  $info['zip']['entries'][] = $fileentry;
88
  } else {
89
- $info['warning'][] = 'Error parsing Local File Header at offset '.$central_directory_entry['entry_offset'];
90
  }
91
  }
92
 
@@ -94,15 +96,15 @@ class getid3_zip extends getid3_handler
94
  !empty($info['zip']['files']['_rels']['.rels']) &&
95
  !empty($info['zip']['files']['docProps']['app.xml']) &&
96
  !empty($info['zip']['files']['docProps']['core.xml'])) {
97
- // http://technet.microsoft.com/en-us/library/cc179224.aspx
98
- $info['fileformat'] = 'zip.msoffice';
99
- if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
100
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
101
- } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
102
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
103
- } elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
104
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
105
- }
106
  }
107
 
108
  return true;
@@ -113,23 +115,25 @@ class getid3_zip extends getid3_handler
113
  if (!$this->getZIPentriesFilepointer()) {
114
  unset($info['zip']);
115
  $info['fileformat'] = '';
116
- $info['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
117
  return false;
118
  }
119
 
120
  // central directory couldn't be found and/or parsed
121
  // scan through actual file data entries, recover as much as possible from probable trucated file
122
  if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) {
123
- $info['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)';
124
  }
125
- $info['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
126
  foreach ($info['zip']['entries'] as $key => $valuearray) {
127
  $info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
128
  }
129
  return true;
130
  }
131
 
132
-
 
 
133
  public function getZIPHeaderFilepointerTopDown() {
134
  $info = &$this->getid3->info;
135
 
@@ -145,26 +149,26 @@ class getid3_zip extends getid3_handler
145
  $info['zip']['entries_count']++;
146
  }
147
  if ($info['zip']['entries_count'] == 0) {
148
- $info['error'][] = 'No Local File Header entries found';
149
  return false;
150
  }
151
 
152
  $info['zip']['entries_count'] = 0;
153
- while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
154
  $info['zip']['central_directory'][] = $centraldirectoryentry;
155
  $info['zip']['entries_count']++;
156
  $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
157
  $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
158
  }
159
  if ($info['zip']['entries_count'] == 0) {
160
- $info['error'][] = 'No Central Directory entries found (truncated file?)';
161
  return false;
162
  }
163
 
164
  if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) {
165
  $info['zip']['end_central_directory'] = $EOCD;
166
  } else {
167
- $info['error'][] = 'No End Of Central Directory entry found (truncated file?)';
168
  return false;
169
  }
170
 
@@ -175,7 +179,9 @@ class getid3_zip extends getid3_handler
175
  return true;
176
  }
177
 
178
-
 
 
179
  public function getZIPentriesFilepointer() {
180
  $info = &$this->getid3->info;
181
 
@@ -191,14 +197,16 @@ class getid3_zip extends getid3_handler
191
  $info['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
192
  }
193
  if ($info['zip']['entries_count'] == 0) {
194
- $info['error'][] = 'No Local File Header entries found';
195
  return false;
196
  }
197
 
198
  return true;
199
  }
200
 
201
-
 
 
202
  public function ZIPparseLocalFileHeader() {
203
  $LocalFileHeader['offset'] = $this->ftell();
204
 
@@ -265,7 +273,7 @@ class getid3_zip extends getid3_handler
265
  $DataDescriptor = $this->fread(16);
266
  $LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
267
  if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08"
268
- $this->getid3->warning[] = 'invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']);
269
  $this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
270
  return false;
271
  }
@@ -278,13 +286,13 @@ class getid3_zip extends getid3_handler
278
  if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) {
279
  // $LocalFileHeader['compressed_size'] already set from Central Directory
280
  } else {
281
- $this->getid3->info['warning'][] = 'conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset'];
282
  }
283
 
284
  if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) {
285
  $LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size'];
286
  } else {
287
- $this->getid3->info['warning'][] = 'conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset'];
288
  }
289
  break;
290
  }
@@ -294,7 +302,9 @@ class getid3_zip extends getid3_handler
294
  return $LocalFileHeader;
295
  }
296
 
297
-
 
 
298
  public function ZIPparseCentralDirectory() {
299
  $CentralDirectory['offset'] = $this->ftell();
300
 
@@ -351,6 +361,9 @@ class getid3_zip extends getid3_handler
351
  return $CentralDirectory;
352
  }
353
 
 
 
 
354
  public function ZIPparseEndOfCentralDirectory() {
355
  $EndOfCentralDirectory['offset'] = $this->ftell();
356
 
@@ -377,9 +390,15 @@ class getid3_zip extends getid3_handler
377
  return $EndOfCentralDirectory;
378
  }
379
 
380
-
 
 
 
 
 
381
  public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
382
  // https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html
 
383
  $ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
384
  // 0x0002 -- see below
385
  // 0x0004 -- see below
@@ -425,7 +444,11 @@ class getid3_zip extends getid3_handler
425
  return $ParsedFlags;
426
  }
427
 
428
-
 
 
 
 
429
  public static function ZIPversionOSLookup($index) {
430
  static $ZIPversionOSLookup = array(
431
  0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
@@ -453,6 +476,11 @@ class getid3_zip extends getid3_handler
453
  return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
454
  }
455
 
 
 
 
 
 
456
  public static function ZIPcompressionMethodLookup($index) {
457
  // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html
458
  static $ZIPcompressionMethodLookup = array(
@@ -484,6 +512,12 @@ class getid3_zip extends getid3_handler
484
  return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
485
  }
486
 
 
 
 
 
 
 
487
  public static function DOStime2UNIXtime($DOSdate, $DOStime) {
488
  // wFatDate
489
  // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.archive.zip.php //
17
 
18
  class getid3_zip extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
32
  $info['zip']['entries_count'] = 0;
33
 
34
  if (!getid3_lib::intValueSupported($info['filesize'])) {
35
+ $this->error('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP');
36
  return false;
37
  } else {
38
  $EOCDsearchData = '';
50
 
51
  $this->fseek($info['zip']['end_central_directory']['directory_offset']);
52
  $info['zip']['entries_count'] = 0;
53
+ while ($centraldirectoryentry = $this->ZIPparseCentralDirectory()) {
54
  $info['zip']['central_directory'][] = $centraldirectoryentry;
55
  $info['zip']['entries_count']++;
56
  $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
63
  }
64
 
65
  if ($info['zip']['entries_count'] == 0) {
66
+ $this->error('No Central Directory entries found (truncated file?)');
67
  return false;
68
  }
69
 
88
  if ($fileentry = $this->ZIPparseLocalFileHeader()) {
89
  $info['zip']['entries'][] = $fileentry;
90
  } else {
91
+ $this->warning('Error parsing Local File Header at offset '.$central_directory_entry['entry_offset']);
92
  }
93
  }
94
 
96
  !empty($info['zip']['files']['_rels']['.rels']) &&
97
  !empty($info['zip']['files']['docProps']['app.xml']) &&
98
  !empty($info['zip']['files']['docProps']['core.xml'])) {
99
+ // http://technet.microsoft.com/en-us/library/cc179224.aspx
100
+ $info['fileformat'] = 'zip.msoffice';
101
+ if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
102
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
103
+ } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
104
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
105
+ } elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
106
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
107
+ }
108
  }
109
 
110
  return true;
115
  if (!$this->getZIPentriesFilepointer()) {
116
  unset($info['zip']);
117
  $info['fileformat'] = '';
118
+ $this->error('Cannot find End Of Central Directory (truncated file?)');
119
  return false;
120
  }
121
 
122
  // central directory couldn't be found and/or parsed
123
  // scan through actual file data entries, recover as much as possible from probable trucated file
124
  if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) {
125
+ $this->error('Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)');
126
  }
127
+ $this->error('Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete');
128
  foreach ($info['zip']['entries'] as $key => $valuearray) {
129
  $info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
130
  }
131
  return true;
132
  }
133
 
134
+ /**
135
+ * @return bool
136
+ */
137
  public function getZIPHeaderFilepointerTopDown() {
138
  $info = &$this->getid3->info;
139
 
149
  $info['zip']['entries_count']++;
150
  }
151
  if ($info['zip']['entries_count'] == 0) {
152
+ $this->error('No Local File Header entries found');
153
  return false;
154
  }
155
 
156
  $info['zip']['entries_count'] = 0;
157
+ while ($centraldirectoryentry = $this->ZIPparseCentralDirectory()) {
158
  $info['zip']['central_directory'][] = $centraldirectoryentry;
159
  $info['zip']['entries_count']++;
160
  $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
161
  $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
162
  }
163
  if ($info['zip']['entries_count'] == 0) {
164
+ $this->error('No Central Directory entries found (truncated file?)');
165
  return false;
166
  }
167
 
168
  if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) {
169
  $info['zip']['end_central_directory'] = $EOCD;
170
  } else {
171
+ $this->error('No End Of Central Directory entry found (truncated file?)');
172
  return false;
173
  }
174
 
179
  return true;
180
  }
181
 
182
+ /**
183
+ * @return bool
184
+ */
185
  public function getZIPentriesFilepointer() {
186
  $info = &$this->getid3->info;
187
 
197
  $info['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
198
  }
199
  if ($info['zip']['entries_count'] == 0) {
200
+ $this->error('No Local File Header entries found');
201
  return false;
202
  }
203
 
204
  return true;
205
  }
206
 
207
+ /**
208
+ * @return array|false
209
+ */
210
  public function ZIPparseLocalFileHeader() {
211
  $LocalFileHeader['offset'] = $this->ftell();
212
 
273
  $DataDescriptor = $this->fread(16);
274
  $LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
275
  if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08"
276
+ $this->getid3->warning('invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']));
277
  $this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
278
  return false;
279
  }
286
  if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) {
287
  // $LocalFileHeader['compressed_size'] already set from Central Directory
288
  } else {
289
+ $this->warning('conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset']);
290
  }
291
 
292
  if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) {
293
  $LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size'];
294
  } else {
295
+ $this->warning('conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset']);
296
  }
297
  break;
298
  }
302
  return $LocalFileHeader;
303
  }
304
 
305
+ /**
306
+ * @return array|false
307
+ */
308
  public function ZIPparseCentralDirectory() {
309
  $CentralDirectory['offset'] = $this->ftell();
310
 
361
  return $CentralDirectory;
362
  }
363
 
364
+ /**
365
+ * @return array|false
366
+ */
367
  public function ZIPparseEndOfCentralDirectory() {
368
  $EndOfCentralDirectory['offset'] = $this->ftell();
369
 
390
  return $EndOfCentralDirectory;
391
  }
392
 
393
+ /**
394
+ * @param int $flagbytes
395
+ * @param int $compressionmethod
396
+ *
397
+ * @return array
398
+ */
399
  public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
400
  // https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html
401
+ $ParsedFlags = array();
402
  $ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
403
  // 0x0002 -- see below
404
  // 0x0004 -- see below
444
  return $ParsedFlags;
445
  }
446
 
447
+ /**
448
+ * @param int $index
449
+ *
450
+ * @return string
451
+ */
452
  public static function ZIPversionOSLookup($index) {
453
  static $ZIPversionOSLookup = array(
454
  0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
476
  return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
477
  }
478
 
479
+ /**
480
+ * @param int $index
481
+ *
482
+ * @return string
483
+ */
484
  public static function ZIPcompressionMethodLookup($index) {
485
  // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html
486
  static $ZIPcompressionMethodLookup = array(
512
  return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
513
  }
514
 
515
+ /**
516
+ * @param int $DOSdate
517
+ * @param int $DOStime
518
+ *
519
+ * @return int
520
+ */
521
  public static function DOStime2UNIXtime($DOSdate, $DOStime) {
522
  // wFatDate
523
  // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
lib/getid3/module.audio-video.asf.php CHANGED
@@ -1,11 +1,10 @@
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.asf.php //
@@ -16,8 +15,11 @@
16
 
17
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
18
 
19
- class getid3_asf extends getid3_handler {
20
-
 
 
 
21
  public function __construct(getID3 $getid3) {
22
  parent::__construct($getid3); // extends getid3_handler::__construct()
23
 
@@ -30,6 +32,9 @@ class getid3_asf extends getid3_handler {
30
  }
31
  }
32
 
 
 
 
33
  public function Analyze() {
34
  $info = &$this->getid3->info;
35
 
@@ -83,6 +88,8 @@ class getid3_asf extends getid3_handler {
83
  $NextObjectOffset = $this->ftell();
84
  $ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30);
85
  $offset = 0;
 
 
86
 
87
  for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
88
  $NextObjectGUID = substr($ASFHeaderData, $offset, 16);
@@ -266,14 +273,14 @@ class getid3_asf extends getid3_handler {
266
  $offset += 16;
267
  $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
268
  if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
269
- $info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';
270
  //return false;
271
  break;
272
  }
273
  $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
274
  $offset += 2;
275
  if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
276
- $info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';
277
  //return false;
278
  break;
279
  }
@@ -316,7 +323,7 @@ class getid3_asf extends getid3_handler {
316
  $offset += 16;
317
  $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
318
  if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
319
- $info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
320
  //return false;
321
  break;
322
  }
@@ -349,7 +356,7 @@ class getid3_asf extends getid3_handler {
349
  if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
350
 
351
  if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
352
- $info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';
353
  } else {
354
 
355
  list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
@@ -412,7 +419,7 @@ class getid3_asf extends getid3_handler {
412
  break;
413
 
414
  default:
415
- $info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';
416
  break;
417
  }
418
 
@@ -458,7 +465,7 @@ class getid3_asf extends getid3_handler {
458
  $offset += 16;
459
  $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
460
  if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
461
- $info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
462
  //return false;
463
  break;
464
  }
@@ -517,7 +524,7 @@ class getid3_asf extends getid3_handler {
517
  $offset += 16;
518
  $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
519
  if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
520
- $info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
521
  break;
522
  }
523
  $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
@@ -525,7 +532,7 @@ class getid3_asf extends getid3_handler {
525
  $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
526
  $offset += 2;
527
  if ($thisfile_asf_markerobject['reserved_2'] != 0) {
528
- $info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';
529
  break;
530
  }
531
  $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
@@ -576,7 +583,7 @@ class getid3_asf extends getid3_handler {
576
  $thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']);
577
  $offset += 16;
578
  if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
579
- $info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';
580
  //return false;
581
  break;
582
  }
@@ -637,7 +644,7 @@ class getid3_asf extends getid3_handler {
637
  break;
638
 
639
  default:
640
- $info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}';
641
  //return false;
642
  break;
643
  }
@@ -761,7 +768,7 @@ class getid3_asf extends getid3_handler {
761
  break;
762
 
763
  default:
764
- $info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';
765
  //return false;
766
  break;
767
  }
@@ -962,26 +969,26 @@ class getid3_asf extends getid3_handler {
962
  default:
963
  // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
964
  if ($this->GUIDname($NextObjectGUIDtext)) {
965
- $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
966
  } else {
967
- $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
968
  }
969
  $offset += ($NextObjectSize - 16 - 8);
970
  break;
971
  }
972
  }
973
- if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) {
974
  $ASFbitrateAudio = 0;
975
  $ASFbitrateVideo = 0;
976
- for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) {
977
  if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) {
978
  switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) {
979
  case 1:
980
- $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
981
  break;
982
 
983
  case 2:
984
- $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
985
  break;
986
 
987
  default:
@@ -1183,7 +1190,7 @@ class getid3_asf extends getid3_handler {
1183
  $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
1184
  $offset += 2;
1185
  if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
1186
- $info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"';
1187
  //return false;
1188
  break;
1189
  }
@@ -1319,9 +1326,9 @@ class getid3_asf extends getid3_handler {
1319
  default:
1320
  // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
1321
  if ($this->GUIDname($NextObjectGUIDtext)) {
1322
- $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8);
1323
  } else {
1324
- $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8);
1325
  }
1326
  $this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR);
1327
  break;
@@ -1405,7 +1412,7 @@ class getid3_asf extends getid3_handler {
1405
  break;
1406
 
1407
  default:
1408
- $info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw'];
1409
  break;
1410
 
1411
  }
@@ -1440,6 +1447,11 @@ class getid3_asf extends getid3_handler {
1440
  return true;
1441
  }
1442
 
 
 
 
 
 
1443
  public static function codecListObjectTypeLookup($CodecListType) {
1444
  static $lookup = array(
1445
  0x0001 => 'Video Codec',
@@ -1450,6 +1462,9 @@ class getid3_asf extends getid3_handler {
1450
  return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type');
1451
  }
1452
 
 
 
 
1453
  public static function KnownGUIDs() {
1454
  static $GUIDarray = array(
1455
  'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A',
@@ -1564,6 +1579,11 @@ class getid3_asf extends getid3_handler {
1564
  return $GUIDarray;
1565
  }
1566
 
 
 
 
 
 
1567
  public static function GUIDname($GUIDstring) {
1568
  static $GUIDarray = array();
1569
  if (empty($GUIDarray)) {
@@ -1572,6 +1592,11 @@ class getid3_asf extends getid3_handler {
1572
  return array_search($GUIDstring, $GUIDarray);
1573
  }
1574
 
 
 
 
 
 
1575
  public static function ASFIndexObjectIndexTypeLookup($id) {
1576
  static $ASFIndexObjectIndexTypeLookup = array();
1577
  if (empty($ASFIndexObjectIndexTypeLookup)) {
@@ -1582,6 +1607,11 @@ class getid3_asf extends getid3_handler {
1582
  return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
1583
  }
1584
 
 
 
 
 
 
1585
  public static function GUIDtoBytestring($GUIDstring) {
1586
  // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
1587
  // first 4 bytes are in little-endian order
@@ -1617,6 +1647,11 @@ class getid3_asf extends getid3_handler {
1617
  return $hexbytecharstring;
1618
  }
1619
 
 
 
 
 
 
1620
  public static function BytestringToGUID($Bytestring) {
1621
  $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
1622
  $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
@@ -1642,6 +1677,12 @@ class getid3_asf extends getid3_handler {
1642
  return strtoupper($GUIDstring);
1643
  }
1644
 
 
 
 
 
 
 
1645
  public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
1646
  // FILETIME is a 64-bit unsigned integer representing
1647
  // the number of 100-nanosecond intervals since January 1, 1601
@@ -1653,6 +1694,11 @@ class getid3_asf extends getid3_handler {
1653
  return ($FILETIME - 116444736000000000) / 10000000;
1654
  }
1655
 
 
 
 
 
 
1656
  public static function WMpictureTypeLookup($WMpictureType) {
1657
  static $lookup = null;
1658
  if ($lookup === null) {
@@ -1684,6 +1730,12 @@ class getid3_asf extends getid3_handler {
1684
  return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
1685
  }
1686
 
 
 
 
 
 
 
1687
  public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
1688
  // http://msdn.microsoft.com/en-us/library/bb643323.aspx
1689
 
@@ -1917,9 +1969,9 @@ class getid3_asf extends getid3_handler {
1917
  default:
1918
  $unhandled_sections++;
1919
  if ($this->GUIDname($thisObject['guid_text'])) {
1920
- $this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8);
1921
  } else {
1922
- $this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8);
1923
  }
1924
  break;
1925
  }
@@ -1930,7 +1982,11 @@ class getid3_asf extends getid3_handler {
1930
  return $HeaderExtensionObjectParsed;
1931
  }
1932
 
1933
-
 
 
 
 
1934
  public static function metadataLibraryObjectDataTypeLookup($id) {
1935
  static $lookup = array(
1936
  0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
@@ -1944,6 +2000,11 @@ class getid3_asf extends getid3_handler {
1944
  return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
1945
  }
1946
 
 
 
 
 
 
1947
  public function ASF_WMpicture(&$data) {
1948
  //typedef struct _WMPicture{
1949
  // LPWSTR pwszMIMEType;
@@ -1994,14 +2055,24 @@ class getid3_asf extends getid3_handler {
1994
  return $WMpicture;
1995
  }
1996
 
1997
-
1998
- // Remove terminator 00 00 and convert UTF-16LE to Latin-1
 
 
 
 
 
1999
  public static function TrimConvert($string) {
2000
  return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
2001
  }
2002
 
2003
-
2004
- // Remove terminator 00 00
 
 
 
 
 
2005
  public static function TrimTerm($string) {
2006
  // remove terminator, only if present (it should be, but...)
2007
  if (substr($string, -2) === "\x00\x00") {
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
+ // available at https://github.com/JamesHeinrich/getID3 //
5
+ // or https://www.getid3.org //
6
+ // or http://getid3.sourceforge.net //
7
+ // see readme.txt for more details //
 
8
  /////////////////////////////////////////////////////////////////
9
  // //
10
  // module.audio-video.asf.php //
15
 
16
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
17
 
18
+ class getid3_asf extends getid3_handler
19
+ {
20
+ /**
21
+ * @param getID3 $getid3
22
+ */
23
  public function __construct(getID3 $getid3) {
24
  parent::__construct($getid3); // extends getid3_handler::__construct()
25
 
32
  }
33
  }
34
 
35
+ /**
36
+ * @return bool
37
+ */
38
  public function Analyze() {
39
  $info = &$this->getid3->info;
40
 
88
  $NextObjectOffset = $this->ftell();
89
  $ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30);
90
  $offset = 0;
91
+ $thisfile_asf_streambitratepropertiesobject = array();
92
+ $thisfile_asf_codeclistobject = array();
93
 
94
  for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
95
  $NextObjectGUID = substr($ASFHeaderData, $offset, 16);
273
  $offset += 16;
274
  $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
275
  if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
276
+ $this->warning('header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')');
277
  //return false;
278
  break;
279
  }
280
  $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
281
  $offset += 2;
282
  if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
283
+ $this->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');
284
  //return false;
285
  break;
286
  }
323
  $offset += 16;
324
  $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
325
  if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
326
+ $this->warning('codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}');
327
  //return false;
328
  break;
329
  }
356
  if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
357
 
358
  if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
359
+ $this->warning('[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-separated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"');
360
  } else {
361
 
362
  list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
419
  break;
420
 
421
  default:
422
+ $this->warning('unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')');
423
  break;
424
  }
425
 
465
  $offset += 16;
466
  $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
467
  if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
468
+ $this->warning('script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}');
469
  //return false;
470
  break;
471
  }
524
  $offset += 16;
525
  $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
526
  if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
527
+ $this->warning('marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}');
528
  break;
529
  }
530
  $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
532
  $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
533
  $offset += 2;
534
  if ($thisfile_asf_markerobject['reserved_2'] != 0) {
535
+ $this->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');
536
  break;
537
  }
538
  $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
583
  $thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']);
584
  $offset += 16;
585
  if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
586
+ $this->warning('bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}');
587
  //return false;
588
  break;
589
  }
644
  break;
645
 
646
  default:
647
+ $this->warning('error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}');
648
  //return false;
649
  break;
650
  }
768
  break;
769
 
770
  default:
771
+ $this->warning('extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')');
772
  //return false;
773
  break;
774
  }
969
  default:
970
  // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
971
  if ($this->GUIDname($NextObjectGUIDtext)) {
972
+ $this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8));
973
  } else {
974
+ $this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8));
975
  }
976
  $offset += ($NextObjectSize - 16 - 8);
977
  break;
978
  }
979
  }
980
+ if (isset($thisfile_asf_streambitratepropertiesobject['bitrate_records_count'])) {
981
  $ASFbitrateAudio = 0;
982
  $ASFbitrateVideo = 0;
983
+ for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) {
984
  if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) {
985
  switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) {
986
  case 1:
987
+ $ASFbitrateVideo += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
988
  break;
989
 
990
  case 2:
991
+ $ASFbitrateAudio += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
992
  break;
993
 
994
  default:
1190
  $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
1191
  $offset += 2;
1192
  if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
1193
+ $this->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
1194
  //return false;
1195
  break;
1196
  }
1326
  default:
1327
  // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
1328
  if ($this->GUIDname($NextObjectGUIDtext)) {
1329
+ $this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8));
1330
  } else {
1331
+ $this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8));
1332
  }
1333
  $this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR);
1334
  break;
1412
  break;
1413
 
1414
  default:
1415
+ $this->warning('Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']);
1416
  break;
1417
 
1418
  }
1447
  return true;
1448
  }
1449
 
1450
+ /**
1451
+ * @param int $CodecListType
1452
+ *
1453
+ * @return string
1454
+ */
1455
  public static function codecListObjectTypeLookup($CodecListType) {
1456
  static $lookup = array(
1457
  0x0001 => 'Video Codec',
1462
  return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type');
1463
  }
1464
 
1465
+ /**
1466
+ * @return array
1467
+ */
1468
  public static function KnownGUIDs() {
1469
  static $GUIDarray = array(
1470
  'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A',
1579
  return $GUIDarray;
1580
  }
1581
 
1582
+ /**
1583
+ * @param string $GUIDstring
1584
+ *
1585
+ * @return string|false
1586
+ */
1587
  public static function GUIDname($GUIDstring) {
1588
  static $GUIDarray = array();
1589
  if (empty($GUIDarray)) {
1592
  return array_search($GUIDstring, $GUIDarray);
1593
  }
1594
 
1595
+ /**
1596
+ * @param int $id
1597
+ *
1598
+ * @return string
1599
+ */
1600
  public static function ASFIndexObjectIndexTypeLookup($id) {
1601
  static $ASFIndexObjectIndexTypeLookup = array();
1602
  if (empty($ASFIndexObjectIndexTypeLookup)) {
1607
  return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
1608
  }
1609
 
1610
+ /**
1611
+ * @param string $GUIDstring
1612
+ *
1613
+ * @return string
1614
+ */
1615
  public static function GUIDtoBytestring($GUIDstring) {
1616
  // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
1617
  // first 4 bytes are in little-endian order
1647
  return $hexbytecharstring;
1648
  }
1649
 
1650
+ /**
1651
+ * @param string $Bytestring
1652
+ *
1653
+ * @return string
1654
+ */
1655
  public static function BytestringToGUID($Bytestring) {
1656
  $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
1657
  $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
1677
  return strtoupper($GUIDstring);
1678
  }
1679
 
1680
+ /**
1681
+ * @param int $FILETIME
1682
+ * @param bool $round
1683
+ *
1684
+ * @return float|int
1685
+ */
1686
  public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
1687
  // FILETIME is a 64-bit unsigned integer representing
1688
  // the number of 100-nanosecond intervals since January 1, 1601
1694
  return ($FILETIME - 116444736000000000) / 10000000;
1695
  }
1696
 
1697
+ /**
1698
+ * @param int $WMpictureType
1699
+ *
1700
+ * @return string
1701
+ */
1702
  public static function WMpictureTypeLookup($WMpictureType) {
1703
  static $lookup = null;
1704
  if ($lookup === null) {
1730
  return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
1731
  }
1732
 
1733
+ /**
1734
+ * @param string $asf_header_extension_object_data
1735
+ * @param int $unhandled_sections
1736
+ *
1737
+ * @return array
1738
+ */
1739
  public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
1740
  // http://msdn.microsoft.com/en-us/library/bb643323.aspx
1741
 
1969
  default:
1970
  $unhandled_sections++;
1971
  if ($this->GUIDname($thisObject['guid_text'])) {
1972
+ $this->warning('unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8));
1973
  } else {
1974
+ $this->warning('unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8));
1975
  }
1976
  break;
1977
  }
1982
  return $HeaderExtensionObjectParsed;
1983
  }
1984
 
1985
+ /**
1986
+ * @param int $id
1987
+ *
1988
+ * @return string
1989
+ */
1990
  public static function metadataLibraryObjectDataTypeLookup($id) {
1991
  static $lookup = array(
1992
  0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
2000
  return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
2001
  }
2002
 
2003
+ /**
2004
+ * @param string $data
2005
+ *
2006
+ * @return array
2007
+ */
2008
  public function ASF_WMpicture(&$data) {
2009
  //typedef struct _WMPicture{
2010
  // LPWSTR pwszMIMEType;
2055
  return $WMpicture;
2056
  }
2057
 
2058
+ /**
2059
+ * Remove terminator 00 00 and convert UTF-16LE to Latin-1.
2060
+ *
2061
+ * @param string $string
2062
+ *
2063
+ * @return string
2064
+ */
2065
  public static function TrimConvert($string) {
2066
  return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
2067
  }
2068
 
2069
+ /**
2070
+ * Remove terminator 00 00.
2071
+ *
2072
+ * @param string $string
2073
+ *
2074
+ * @return string
2075
+ */
2076
  public static function TrimTerm($string) {
2077
  // remove terminator, only if present (it should be, but...)
2078
  if (substr($string, -2) === "\x00\x00") {
lib/getid3/module.audio-video.bink.php CHANGED
@@ -1,11 +1,10 @@
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.bink.php //
@@ -17,11 +16,13 @@
17
 
18
  class getid3_bink extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
24
- $info['error'][] = 'Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']';
25
 
26
  $this->fseek($info['avdataoffset']);
27
  $fileTypeID = $this->fread(3);
@@ -35,7 +36,7 @@ $info['error'][] = 'Bink / Smacker files not properly processed by this version
35
  break;
36
 
37
  default:
38
- $info['error'][] = 'Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"';
39
  return false;
40
  break;
41
  }
@@ -44,6 +45,9 @@ $info['error'][] = 'Bink / Smacker files not properly processed by this version
44
 
45
  }
46
 
 
 
 
47
  public function ParseBink() {
48
  $info = &$this->getid3->info;
49
  $info['fileformat'] = 'bink';
@@ -55,12 +59,15 @@ $info['error'][] = 'Bink / Smacker files not properly processed by this version
55
  $info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2));
56
 
57
  if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) {
58
- $info['error'][] = 'Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']);
59
  }
60
 
61
  return true;
62
  }
63
 
 
 
 
64
  public function ParseSmacker() {
65
  $info = &$this->getid3->info;
66
  $info['fileformat'] = 'smacker';
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
+ // available at https://github.com/JamesHeinrich/getID3 //
5
+ // or https://www.getid3.org //
6
+ // or http://getid3.sourceforge.net //
7
+ // see readme.txt for more details //
 
8
  /////////////////////////////////////////////////////////////////
9
  // //
10
  // module.audio.bink.php //
16
 
17
  class getid3_bink extends getid3_handler
18
  {
19
+ /**
20
+ * @return bool
21
+ */
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
25
+ $this->error('Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']');
26
 
27
  $this->fseek($info['avdataoffset']);
28
  $fileTypeID = $this->fread(3);
36
  break;
37
 
38
  default:
39
+ $this->error('Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"');
40
  return false;
41
  break;
42
  }
45
 
46
  }
47
 
48
+ /**
49
+ * @return bool
50
+ */
51
  public function ParseBink() {
52
  $info = &$this->getid3->info;
53
  $info['fileformat'] = 'bink';
59
  $info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2));
60
 
61
  if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) {
62
+ $this->error('Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']));
63
  }
64
 
65
  return true;
66
  }
67
 
68
+ /**
69
+ * @return bool
70
+ */
71
  public function ParseSmacker() {
72
  $info = &$this->getid3->info;
73
  $info['fileformat'] = 'smacker';
lib/getid3/module.audio-video.flv.php CHANGED
@@ -1,15 +1,22 @@
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
 
 
 
 
 
 
 
 
7
  // //
8
  // FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
9
  // //
10
  // * version 0.1 (26 June 2005) //
11
  // //
12
- // //
13
  // * version 0.1.1 (15 July 2005) //
14
  // minor modifications by James Heinrich <info@getid3.org> //
15
  // //
@@ -43,12 +50,6 @@
43
  // handle GETID3_FLV_VIDEO_VP6FLV_ALPHA //
44
  // improved AVCSequenceParameterSetReader::readData() //
45
  // by Xander Schouwerwou <schouwerwouØgmail*com> //
46
- // //
47
- /////////////////////////////////////////////////////////////////
48
- // //
49
- // module.audio-video.flv.php //
50
- // module for analyzing Shockwave Flash Video files //
51
- // dependencies: NONE //
52
  // ///
53
  /////////////////////////////////////////////////////////////////
54
 
@@ -73,12 +74,21 @@ define('H264_PROFILE_HIGH422', 122);
73
  define('H264_PROFILE_HIGH444', 144);
74
  define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
75
 
76
- class getid3_flv extends getid3_handler {
77
-
78
  const magic = 'FLV';
79
 
80
- public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
81
-
 
 
 
 
 
 
 
 
 
82
  public function Analyze() {
83
  $info = &$this->getid3->info;
84
 
@@ -93,7 +103,7 @@ class getid3_flv extends getid3_handler {
93
  $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
94
 
95
  if ($info['flv']['header']['signature'] != self::magic) {
96
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
97
  unset($info['flv'], $info['fileformat']);
98
  return false;
99
  }
@@ -332,7 +342,11 @@ class getid3_flv extends getid3_handler {
332
  return true;
333
  }
334
 
335
-
 
 
 
 
336
  public static function audioFormatLookup($id) {
337
  static $lookup = array(
338
  0 => 'Linear PCM, platform endian',
@@ -355,6 +369,11 @@ class getid3_flv extends getid3_handler {
355
  return (isset($lookup[$id]) ? $lookup[$id] : false);
356
  }
357
 
 
 
 
 
 
358
  public static function audioRateLookup($id) {
359
  static $lookup = array(
360
  0 => 5500,
@@ -365,6 +384,11 @@ class getid3_flv extends getid3_handler {
365
  return (isset($lookup[$id]) ? $lookup[$id] : false);
366
  }
367
 
 
 
 
 
 
368
  public static function audioBitDepthLookup($id) {
369
  static $lookup = array(
370
  0 => 8,
@@ -373,6 +397,11 @@ class getid3_flv extends getid3_handler {
373
  return (isset($lookup[$id]) ? $lookup[$id] : false);
374
  }
375
 
 
 
 
 
 
376
  public static function videoCodecLookup($id) {
377
  static $lookup = array(
378
  GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
@@ -386,47 +415,84 @@ class getid3_flv extends getid3_handler {
386
  }
387
  }
388
 
389
- class AMFStream {
 
 
 
 
390
  public $bytes;
 
 
 
 
391
  public $pos;
392
 
 
 
 
393
  public function __construct(&$bytes) {
394
  $this->bytes =& $bytes;
395
  $this->pos = 0;
396
  }
397
 
398
- public function readByte() {
399
- return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
 
 
 
400
  }
401
 
402
- public function readInt() {
 
 
 
403
  return ($this->readByte() << 8) + $this->readByte();
404
  }
405
 
406
- public function readLong() {
 
 
 
407
  return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
408
  }
409
 
 
 
 
410
  public function readDouble() {
411
  return getid3_lib::BigEndian2Float($this->read(8));
412
  }
413
 
 
 
 
414
  public function readUTF() {
415
  $length = $this->readInt();
416
  return $this->read($length);
417
  }
418
 
 
 
 
419
  public function readLongUTF() {
420
  $length = $this->readLong();
421
  return $this->read($length);
422
  }
423
 
 
 
 
 
 
424
  public function read($length) {
425
  $val = substr($this->bytes, $this->pos, $length);
426
  $this->pos += $length;
427
  return $val;
428
  }
429
 
 
 
 
430
  public function peekByte() {
431
  $pos = $this->pos;
432
  $val = $this->readByte();
@@ -434,6 +500,9 @@ class AMFStream {
434
  return $val;
435
  }
436
 
 
 
 
437
  public function peekInt() {
438
  $pos = $this->pos;
439
  $val = $this->readInt();
@@ -441,6 +510,9 @@ class AMFStream {
441
  return $val;
442
  }
443
 
 
 
 
444
  public function peekLong() {
445
  $pos = $this->pos;
446
  $val = $this->readLong();
@@ -448,6 +520,9 @@ class AMFStream {
448
  return $val;
449
  }
450
 
 
 
 
451
  public function peekDouble() {
452
  $pos = $this->pos;
453
  $val = $this->readDouble();
@@ -455,6 +530,9 @@ class AMFStream {
455
  return $val;
456
  }
457
 
 
 
 
458
  public function peekUTF() {
459
  $pos = $this->pos;
460
  $val = $this->readUTF();
@@ -462,6 +540,9 @@ class AMFStream {
462
  return $val;
463
  }
464
 
 
 
 
465
  public function peekLongUTF() {
466
  $pos = $this->pos;
467
  $val = $this->readLongUTF();
@@ -470,13 +551,23 @@ class AMFStream {
470
  }
471
  }
472
 
473
- class AMFReader {
 
 
 
 
474
  public $stream;
475
 
476
- public function __construct(&$stream) {
477
- $this->stream =& $stream;
 
 
 
478
  }
479
 
 
 
 
480
  public function readData() {
481
  $value = null;
482
 
@@ -547,23 +638,36 @@ class AMFReader {
547
  return $value;
548
  }
549
 
 
 
 
550
  public function readDouble() {
551
  return $this->stream->readDouble();
552
  }
553
 
 
 
 
554
  public function readBoolean() {
555
  return $this->stream->readByte() == 1;
556
  }
557
 
 
 
 
558
  public function readString() {
559
  return $this->stream->readUTF();
560
  }
561
 
 
 
 
562
  public function readObject() {
563
  // Get highest numerical index - ignored
564
  // $highestIndex = $this->stream->readLong();
565
 
566
  $data = array();
 
567
 
568
  while ($key = $this->stream->readUTF()) {
569
  $data[$key] = $this->readData();
@@ -576,15 +680,19 @@ class AMFReader {
576
  return $data;
577
  }
578
 
 
 
 
579
  public function readMixedArray() {
580
  // Get highest numerical index - ignored
581
  $highestIndex = $this->stream->readLong();
582
 
583
  $data = array();
 
584
 
585
  while ($key = $this->stream->readUTF()) {
586
  if (is_numeric($key)) {
587
- $key = (float) $key;
588
  }
589
  $data[$key] = $this->readData();
590
  }
@@ -597,6 +705,9 @@ class AMFReader {
597
  return $data;
598
  }
599
 
 
 
 
600
  public function readArray() {
601
  $length = $this->stream->readLong();
602
  $data = array();
@@ -607,34 +718,61 @@ class AMFReader {
607
  return $data;
608
  }
609
 
 
 
 
610
  public function readDate() {
611
  $timestamp = $this->stream->readDouble();
612
  $timezone = $this->stream->readInt();
613
  return $timestamp;
614
  }
615
 
 
 
 
616
  public function readLongString() {
617
  return $this->stream->readLongUTF();
618
  }
619
 
 
 
 
620
  public function readXML() {
621
  return $this->stream->readLongUTF();
622
  }
623
 
 
 
 
624
  public function readTypedObject() {
625
  $className = $this->stream->readUTF();
626
  return $this->readObject();
627
  }
628
  }
629
 
630
- class AVCSequenceParameterSetReader {
 
 
 
 
631
  public $sps;
632
  public $start = 0;
633
  public $currentBytes = 0;
634
  public $currentBits = 0;
 
 
 
 
635
  public $width;
 
 
 
 
636
  public $height;
637
 
 
 
 
638
  public function __construct($sps) {
639
  $this->sps = $sps;
640
  }
@@ -691,18 +829,29 @@ class AVCSequenceParameterSetReader {
691
  }
692
  }
693
 
 
 
 
694
  public function skipBits($bits) {
695
  $newBits = $this->currentBits + $bits;
696
  $this->currentBytes += (int)floor($newBits / 8);
697
  $this->currentBits = $newBits % 8;
698
  }
699
 
 
 
 
700
  public function getBit() {
701
  $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
702
  $this->skipBits(1);
703
  return $result;
704
  }
705
 
 
 
 
 
 
706
  public function getBits($bits) {
707
  $result = 0;
708
  for ($i = 0; $i < $bits; $i++) {
@@ -711,6 +860,9 @@ class AVCSequenceParameterSetReader {
711
  return $result;
712
  }
713
 
 
 
 
714
  public function expGolombUe() {
715
  $significantBits = 0;
716
  $bit = $this->getBit();
@@ -726,6 +878,9 @@ class AVCSequenceParameterSetReader {
726
  return (1 << $significantBits) + $this->getBits($significantBits) - 1;
727
  }
728
 
 
 
 
729
  public function expGolombSe() {
730
  $result = $this->expGolombUe();
731
  if (($result & 0x01) == 0) {
@@ -735,10 +890,16 @@ class AVCSequenceParameterSetReader {
735
  }
736
  }
737
 
 
 
 
738
  public function getWidth() {
739
  return $this->width;
740
  }
741
 
 
 
 
742
  public function getHeight() {
743
  return $this->height;
744
  }
1
  <?php
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
+ // available at https://github.com/JamesHeinrich/getID3 //
5
+ // or https://www.getid3.org //
6
+ // or http://getid3.sourceforge.net //
7
+ // see readme.txt for more details //
8
+ /////////////////////////////////////////////////////////////////
9
+ // //
10
+ // module.audio-video.flv.php //
11
+ // module for analyzing Shockwave Flash Video files //
12
+ // dependencies: NONE //
13
+ // //
14
+ /////////////////////////////////////////////////////////////////
15
  // //
16
  // FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
17
  // //
18
  // * version 0.1 (26 June 2005) //
19
  // //
 
20
  // * version 0.1.1 (15 July 2005) //
21
  // minor modifications by James Heinrich <info@getid3.org> //
22
  // //
50
  // handle GETID3_FLV_VIDEO_VP6FLV_ALPHA //
51
  // improved AVCSequenceParameterSetReader::readData() //
52
  // by Xander Schouwerwou <schouwerwouØgmail*com> //
 
 
 
 
 
 
53
  // ///
54
  /////////////////////////////////////////////////////////////////
55
 
74
  define('H264_PROFILE_HIGH444', 144);
75
  define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
76
 
77
+ class getid3_flv extends getid3_handler
78
+ {
79
  const magic = 'FLV';
80
 
81
+ /**
82
+ * Break out of the loop if too many frames have been scanned; only scan this
83
+ * many if meta frame does not contain useful duration.
84
+ *
85
+ * @var int
86
+ */
87
+ public $max_frames = 100000;
88
+
89
+ /**
90
+ * @return bool
91
+ */
92
  public function Analyze() {
93
  $info = &$this->getid3->info;
94
 
103
  $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
104
 
105
  if ($info['flv']['header']['signature'] != self::magic) {
106
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"');
107
  unset($info['flv'], $info['fileformat']);
108
  return false;
109
  }
342
  return true;
343
  }
344
 
345
+ /**
346
+ * @param int $id
347
+ *
348
+ * @return string|false
349
+ */
350
  public static function audioFormatLookup($id) {
351
  static $lookup = array(
352
  0 => 'Linear PCM, platform endian',
369
  return (isset($lookup[$id]) ? $lookup[$id] : false);
370
  }
371
 
372
+ /**
373
+ * @param int $id
374
+ *
375
+ * @return int|false
376
+ */
377
  public static function audioRateLookup($id) {
378
  static $lookup = array(
379
  0 => 5500,
384
  return (isset($lookup[$id]) ? $lookup[$id] : false);
385
  }
386
 
387
+ /**
388
+ * @param int $id
389
+ *
390
+ * @return int|false
391
+ */
392
  public static function audioBitDepthLookup($id) {
393
  static $lookup = array(
394
  0 => 8,
397
  return (isset($lookup[$id]) ? $lookup[$id] : false);
398
  }
399
 
400
+ /**
401
+ * @param int $id
402
+ *
403
+ * @return string|false
404
+ */
405
  public static function videoCodecLookup($id) {
406
  static $lookup = array(
407
  GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
415
  }
416
  }
417
 
418
+ class AMFStream
419
+ {
420
+ /**
421
+ * @var string
422
+ */
423
  public $bytes;
424
+
425
+ /**
426
+ * @var int
427
+ */
428
  public $pos;
429
 
430
+ /**
431
+ * @param string $bytes
432
+ */
433
  public function __construct(&$bytes) {
434
  $this->bytes =& $bytes;
435
  $this->pos = 0;
436
  }
437
 
438
+ /**
439
+ * @return int
440
+ */
441
+ public function readByte() { // 8-bit
442
+ return ord(substr($this->bytes, $this->pos++, 1));
443
  }
444
 
445
+ /**
446
+ * @return int
447
+ */
448
+ public function readInt() { // 16-bit
449
  return ($this->readByte() << 8) + $this->readByte();
450
  }
451
 
452
+ /**
453
+ * @return int
454
+ */
455
+ public function readLong() { // 32-bit
456
  return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
457
  }
458
 
459
+ /**
460
+ * @return float|false
461
+ */
462
  public function readDouble() {
463
  return getid3_lib::BigEndian2Float($this->read(8));
464
  }
465
 
466
+ /**
467
+ * @return string
468
+ */
469
  public function readUTF() {
470
  $length = $this->readInt();
471
  return $this->read($length);
472
  }
473
 
474
+ /**
475
+ * @return string
476
+ */
477
  public function readLongUTF() {
478
  $length = $this->readLong();
479
  return $this->read($length);
480
  }
481
 
482
+ /**
483
+ * @param int $length
484
+ *
485
+ * @return string
486
+ */
487
  public function read($length) {
488
  $val = substr($this->bytes, $this->pos, $length);
489
  $this->pos += $length;
490
  return $val;
491
  }
492
 
493
+ /**
494
+ * @return int
495
+ */
496
  public function peekByte() {
497
  $pos = $this->pos;
498
  $val = $this->readByte();
500
  return $val;
501
  }
502
 
503
+ /**
504
+ * @return int
505
+ */
506
  public function peekInt() {
507
  $pos = $this->pos;
508
  $val = $this->readInt();
510
  return $val;
511
  }
512
 
513
+ /**
514
+ * @return int
515
+ */
516
  public function peekLong() {
517
  $pos = $this->pos;
518
  $val = $this->readLong();
520
  return $val;
521
  }
522
 
523
+ /**
524
+ * @return float|false
525
+ */
526
  public function peekDouble() {
527
  $pos = $this->pos;
528
  $val = $this->readDouble();
530
  return $val;
531
  }
532
 
533
+ /**
534
+ * @return string
535
+ */
536
  public function peekUTF() {
537
  $pos = $this->pos;
538
  $val = $this->readUTF();
540
  return $val;
541
  }
542
 
543
+ /**
544
+ * @return string
545
+ */
546
  public function peekLongUTF() {
547
  $pos = $this->pos;
548
  $val = $this->readLongUTF();
551
  }
552
  }
553
 
554
+ class AMFReader
555
+ {
556
+ /**
557
+ * @var AMFStream
558
+ */
559
  public $stream;
560
 
561
+ /**
562
+ * @param AMFStream $stream
563
+ */
564
+ public function __construct(AMFStream $stream) {
565
+ $this->stream = $stream;
566
  }
567
 
568
+ /**
569
+ * @return mixed
570
+ */
571
  public function readData() {
572
  $value = null;
573
 
638
  return $value;
639
  }
640
 
641
+ /**
642
+ * @return float|false
643
+ */
644
  public function readDouble() {
645
  return $this->stream->readDouble();
646
  }
647
 
648
+ /**
649
+ * @return bool
650
+ */
651
  public function readBoolean() {
652
  return $this->stream->readByte() == 1;
653
  }
654
 
655
+ /**
656
+ * @return string
657
+ */
658
  public function readString() {
659
  return $this->stream->readUTF();
660
  }
661
 
662
+ /**
663
+ * @return array
664
+ */
665
  public function readObject() {
666
  // Get highest numerical index - ignored
667
  // $highestIndex = $this->stream->readLong();
668
 
669
  $data = array();
670
+ $key = null;
671
 
672
  while ($key = $this->stream->readUTF()) {
673
  $data[$key] = $this->readData();
680
  return $data;
681
  }
682
 
683
+ /**
684
+ * @return array
685
+ */
686
  public function readMixedArray() {
687
  // Get highest numerical index - ignored
688
  $highestIndex = $this->stream->readLong();
689
 
690
  $data = array();
691
+ $key = null;
692
 
693
  while ($key = $this->stream->readUTF()) {
694
  if (is_numeric($key)) {
695
+ $key = (int) $key;
696
  }
697
  $data[$key] = $this->readData();
698
  }
705
  return $data;
706
  }
707
 
708
+ /**
709
+ * @return array
710
+ */
711
  public function readArray() {
712
  $length = $this->stream->readLong();
713
  $data = array();
718
  return $data;
719
  }
720
 
721
+ /**
722
+ * @return float|false
723
+ */
724
  public function readDate() {
725
  $timestamp = $this->stream->readDouble();
726
  $timezone = $this->stream->readInt();
727
  return $timestamp;
728
  }
729
 
730
+ /**
731
+ * @return string
732
+ */
733
  public function readLongString() {
734
  return $this->stream->readLongUTF();
735
  }
736
 
737
+ /**
738
+ * @return string
739
+ */
740
  public function readXML() {
741
  return $this->stream->readLongUTF();
742
  }
743
 
744
+ /**
745
+ * @return array
746
+ */
747
  public function readTypedObject() {
748
  $className = $this->stream->readUTF();
749
  return $this->readObject();
750
  }
751
  }
752
 
753
+ class AVCSequenceParameterSetReader
754
+ {
755
+ /**
756
+ * @var string
757
+ */
758
  public $sps;
759
  public $start = 0;
760
  public $currentBytes = 0;
761
  public $currentBits = 0;
762
+
763
+ /**
764
+ * @var int
765
+ */
766
  public $width;
767
+
768
+ /**
769
+ * @var int
770
+ */
771
  public $height;
772
 
773
+ /**
774
+ * @param string $sps
775
+ */
776
  public function __construct($sps) {
777
  $this->sps = $sps;
778
  }
829
  }
830
  }
831
 
832
+ /**
833
+ * @param int $bits
834
+ */
835
  public function skipBits($bits) {
836
  $newBits = $this->currentBits + $bits;
837
  $this->currentBytes += (int)floor($newBits / 8);
838
  $this->currentBits = $newBits % 8;
839
  }
840
 
841
+ /**
842
+ * @return int
843
+ */
844
  public function getBit() {
845
  $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
846
  $this->skipBits(1);
847
  return $result;
848
  }
849
 
850
+ /**
851
+ * @param int $bits
852
+ *
853
+ * @return int
854
+ */
855
  public function getBits($bits) {
856
  $result = 0;
857
  for ($i = 0; $i < $bits; $i++) {
860
  return $result;
861
  }
862
 
863
+ /**
864
+ * @return int
865
+ */
866
  public function expGolombUe() {
867
  $significantBits = 0;
868
  $bit = $this->getBit();
878
  return (1 << $significantBits) + $this->getBits($significantBits) - 1;
879
  }
880
 
881
+ /**
882
+ * @return int
883
+ */
884
  public function expGolombSe() {
885
  $result = $this->expGolombUe();
886
  if (($result & 0x01) == 0) {
890
  }
891
  }
892
 
893
+ /**
894
+ * @return int
895
+ */
896
  public function getWidth() {
897
  return $this->width;
898
  }
899
 
900
+ /**
901
+ * @return int
902
+ */
903
  public function getHeight() {
904
  return $this->height;
905
  }
lib/getid3/module.audio-video.matroska.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.matriska.php //
@@ -72,7 +72,7 @@ define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] --
72
  define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
73
  define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
74
  define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
75
- define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
76
  define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
77
  define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
78
  define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
@@ -215,17 +215,33 @@ define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] --
215
  */
216
  class getid3_matroska extends getid3_handler
217
  {
218
- // public options
219
- public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
220
- public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE]
221
-
222
- // private parser settings/placeholders
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  private $EBMLbuffer = '';
224
  private $EBMLbuffer_offset = 0;
225
  private $EBMLbuffer_length = 0;
226
  private $current_offset = 0;
227
  private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
228
 
 
 
 
229
  public function Analyze()
230
  {
231
  $info = &$this->getid3->info;
@@ -234,7 +250,7 @@ class getid3_matroska extends getid3_handler
234
  try {
235
  $this->parseEBML($info);
236
  } catch (Exception $e) {
237
- $info['error'][] = 'EBML parser: '.$e->getMessage();
238
  }
239
 
240
  // calculate playtime
@@ -330,11 +346,13 @@ class getid3_matroska extends getid3_handler
330
  break;
331
 
332
  case 'A_AC3':
 
333
  case 'A_DTS':
334
  case 'A_MPEG/L3':
335
  case 'A_MPEG/L2':
336
  case 'A_FLAC':
337
- getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, true);
 
338
 
339
  if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
340
  $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
@@ -352,7 +370,7 @@ class getid3_matroska extends getid3_handler
352
  }
353
 
354
  // analyze
355
- $class = 'getid3_'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);
356
  $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
357
  $getid3_audio = new $class($getid3_temp, __CLASS__);
358
  if ($track_info['dataformat'] == 'flac') {
@@ -364,8 +382,8 @@ class getid3_matroska extends getid3_handler
364
  if (!empty($getid3_temp->info[$header_data_key])) {
365
  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
366
  if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
367
- foreach ($getid3_temp->info['audio'] as $key => $value) {
368
- $track_info[$key] = $value;
369
  }
370
  }
371
  }
@@ -419,8 +437,8 @@ class getid3_matroska extends getid3_handler
419
  if (!empty($getid3_temp->info['ogg'])) {
420
  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
421
  if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
422
- foreach ($getid3_temp->info['audio'] as $key => $value) {
423
- $track_info[$key] = $value;
424
  }
425
  }
426
  }
@@ -447,9 +465,9 @@ class getid3_matroska extends getid3_handler
447
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
448
 
449
  $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
450
- foreach ($parsed as $key => $value) {
451
- if ($key != 'raw') {
452
- $track_info[$key] = $value;
453
  }
454
  }
455
  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
@@ -494,6 +512,9 @@ class getid3_matroska extends getid3_handler
494
  return true;
495
  }
496
 
 
 
 
497
  private function parseEBML(&$info) {
498
  // http://www.matroska.org/technical/specs/index.html#EBMLBasics
499
  $this->current_offset = $info['avdataoffset'];
@@ -566,8 +587,11 @@ class getid3_matroska extends getid3_handler
566
  $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
567
  break;
568
  }
569
-
570
- if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
 
 
 
571
  $info['matroska']['seek'][] = $seek_entry;
572
  }
573
  break;
@@ -1223,6 +1247,11 @@ class getid3_matroska extends getid3_handler
1223
  }
1224
  }
1225
 
 
 
 
 
 
1226
  private function EnsureBufferHasEnoughData($min_data=1024) {
1227
  if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
1228
  $read_bytes = max($min_data, $this->getid3->fread_buffer_size());
@@ -1244,6 +1273,9 @@ class getid3_matroska extends getid3_handler
1244
  return true;
1245
  }
1246
 
 
 
 
1247
  private function readEBMLint() {
1248
  $actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
1249
 
@@ -1276,6 +1308,12 @@ class getid3_matroska extends getid3_handler
1276
  return $int_value;
1277
  }
1278
 
 
 
 
 
 
 
1279
  private function readEBMLelementData($length, $check_buffer=false) {
1280
  if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
1281
  return false;
@@ -1285,6 +1323,13 @@ class getid3_matroska extends getid3_handler
1285
  return $data;
1286
  }
1287
 
 
 
 
 
 
 
 
1288
  private function getEBMLelement(&$element, $parent_end, $get_data=false) {
1289
  if ($this->current_offset >= $parent_end) {
1290
  return false;
@@ -1321,6 +1366,11 @@ class getid3_matroska extends getid3_handler
1321
  return true;
1322
  }
1323
 
 
 
 
 
 
1324
  private function unhandledElement($type, $line, $element) {
1325
  // warn only about unknown and missed elements, not about unuseful
1326
  if (!in_array($element['id'], $this->unuseful_elements)) {
@@ -1333,6 +1383,11 @@ class getid3_matroska extends getid3_handler
1333
  }
1334
  }
1335
 
 
 
 
 
 
1336
  private function ExtractCommentsSimpleTag($SimpleTagArray) {
1337
  if (!empty($SimpleTagArray['SimpleTag'])) {
1338
  foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
@@ -1348,6 +1403,11 @@ class getid3_matroska extends getid3_handler
1348
  return true;
1349
  }
1350
 
 
 
 
 
 
1351
  private function HandleEMBLSimpleTag($parent_end) {
1352
  $simpletag_entry = array();
1353
 
@@ -1378,6 +1438,13 @@ class getid3_matroska extends getid3_handler
1378
  return $simpletag_entry;
1379
  }
1380
 
 
 
 
 
 
 
 
1381
  private function HandleEMBLClusterBlock($element, $block_type, &$info) {
1382
  // http://www.matroska.org/technical/specs/index.html#block_structure
1383
  // http://www.matroska.org/technical/specs/index.html#simpleblock_structure
@@ -1441,6 +1508,11 @@ class getid3_matroska extends getid3_handler
1441
  return $block_data;
1442
  }
1443
 
 
 
 
 
 
1444
  private static function EBML2Int($EBMLstring) {
1445
  // http://matroska.org/specs/
1446
 
@@ -1483,12 +1555,22 @@ class getid3_matroska extends getid3_handler
1483
  return getid3_lib::BigEndian2Int($EBMLstring);
1484
  }
1485
 
 
 
 
 
 
1486
  private static function EBMLdate2unix($EBMLdatestamp) {
1487
  // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
1488
  // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
1489
  return round(($EBMLdatestamp / 1000000000) + 978307200);
1490
  }
1491
 
 
 
 
 
 
1492
  public static function TargetTypeValue($target_type) {
1493
  // http://www.matroska.org/technical/specs/tagging/index.html
1494
  static $TargetTypeValue = array();
@@ -1504,6 +1586,11 @@ class getid3_matroska extends getid3_handler
1504
  return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
1505
  }
1506
 
 
 
 
 
 
1507
  public static function BlockLacingType($lacingtype) {
1508
  // http://matroska.org/technical/specs/index.html#block_structure
1509
  static $BlockLacingType = array();
@@ -1516,6 +1603,11 @@ class getid3_matroska extends getid3_handler
1516
  return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
1517
  }
1518
 
 
 
 
 
 
1519
  public static function CodecIDtoCommonName($codecid) {
1520
  // http://www.matroska.org/technical/specs/codecid/index.html
1521
  static $CodecIDlist = array();
@@ -1523,6 +1615,7 @@ class getid3_matroska extends getid3_handler
1523
  $CodecIDlist['A_AAC'] = 'aac';
1524
  $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac';
1525
  $CodecIDlist['A_AC3'] = 'ac3';
 
1526
  $CodecIDlist['A_DTS'] = 'dts';
1527
  $CodecIDlist['A_FLAC'] = 'flac';
1528
  $CodecIDlist['A_MPEG/L1'] = 'mp1';
@@ -1551,6 +1644,11 @@ class getid3_matroska extends getid3_handler
1551
  return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
1552
  }
1553
 
 
 
 
 
 
1554
  private static function EBMLidName($value) {
1555
  static $EBMLidList = array();
1556
  if (empty($EBMLidList)) {
@@ -1749,6 +1847,11 @@ class getid3_matroska extends getid3_handler
1749
  return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
1750
  }
1751
 
 
 
 
 
 
1752
  public static function displayUnit($value) {
1753
  // http://www.matroska.org/technical/specs/index.html#DisplayUnit
1754
  static $units = array(
@@ -1760,8 +1863,14 @@ class getid3_matroska extends getid3_handler
1760
  return (isset($units[$value]) ? $units[$value] : 'unknown');
1761
  }
1762
 
 
 
 
 
 
1763
  private static function getDefaultStreamInfo($streams)
1764
  {
 
1765
  foreach (array_reverse($streams) as $stream) {
1766
  if ($stream['default']) {
1767
  break;
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.matriska.php //
72
  define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
73
  define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
74
  define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
75
+ define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the data was encrypted with.
76
  define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
77
  define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
78
  define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
215
  */
216
  class getid3_matroska extends getid3_handler
217
  {
218
+ /**
219
+ * If true, do not return information about CLUSTER chunks, since there's a lot of them
220
+ * and they're not usually useful [default: TRUE].
221
+ *
222
+ * @var bool
223
+ */
224
+ public static $hide_clusters = true;
225
+
226
+ /**
227
+ * True to parse the whole file, not only header [default: FALSE].
228
+ *
229
+ * @var bool
230
+ */
231
+ public static $parse_whole_file = false;
232
+
233
+ /*
234
+ * Private parser settings/placeholders.
235
+ */
236
  private $EBMLbuffer = '';
237
  private $EBMLbuffer_offset = 0;
238
  private $EBMLbuffer_length = 0;
239
  private $current_offset = 0;
240
  private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
241
 
242
+ /**
243
+ * @return bool
244
+ */
245
  public function Analyze()
246
  {
247
  $info = &$this->getid3->info;
250
  try {
251
  $this->parseEBML($info);
252
  } catch (Exception $e) {
253
+ $this->error('EBML parser: '.$e->getMessage());
254
  }
255
 
256
  // calculate playtime
346
  break;
347
 
348
  case 'A_AC3':
349
+ case 'A_EAC3':
350
  case 'A_DTS':
351
  case 'A_MPEG/L3':
352
  case 'A_MPEG/L2':
353
  case 'A_FLAC':
354
+ $module_dataformat = ($track_info['dataformat'] == 'mp2' ? 'mp3' : ($track_info['dataformat'] == 'eac3' ? 'ac3' : $track_info['dataformat']));
355
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.$module_dataformat.'.php', __FILE__, true);
356
 
357
  if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
358
  $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
370
  }
371
 
372
  // analyze
373
+ $class = 'getid3_'.$module_dataformat;
374
  $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
375
  $getid3_audio = new $class($getid3_temp, __CLASS__);
376
  if ($track_info['dataformat'] == 'flac') {
382
  if (!empty($getid3_temp->info[$header_data_key])) {
383
  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
384
  if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
385
+ foreach ($getid3_temp->info['audio'] as $sub_key => $value) {
386
+ $track_info[$sub_key] = $value;
387
  }
388
  }
389
  }
437
  if (!empty($getid3_temp->info['ogg'])) {
438
  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
439
  if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
440
+ foreach ($getid3_temp->info['audio'] as $sub_key => $value) {
441
+ $track_info[$sub_key] = $value;
442
  }
443
  }
444
  }
465
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
466
 
467
  $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
468
+ foreach ($parsed as $sub_key => $value) {
469
+ if ($sub_key != 'raw') {
470
+ $track_info[$sub_key] = $value;
471
  }
472
  }
473
  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
512
  return true;
513
  }
514
 
515
+ /**
516
+ * @param array $info
517
+ */
518
  private function parseEBML(&$info) {
519
  // http://www.matroska.org/technical/specs/index.html#EBMLBasics
520
  $this->current_offset = $info['avdataoffset'];
587
  $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
588
  break;
589
  }
590
+ if (!isset($seek_entry['target_id'])) {
591
+ $this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']);
592
+ break;
593
+ }
594
+ if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required
595
  $info['matroska']['seek'][] = $seek_entry;
596
  }
597
  break;
1247
  }
1248
  }
1249
 
1250
+ /**
1251
+ * @param int $min_data
1252
+ *
1253
+ * @return bool
1254
+ */
1255
  private function EnsureBufferHasEnoughData($min_data=1024) {
1256
  if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
1257
  $read_bytes = max($min_data, $this->getid3->fread_buffer_size());
1273
  return true;
1274
  }
1275
 
1276
+ /**
1277
+ * @return int|float|false
1278
+ */
1279
  private function readEBMLint() {
1280
  $actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
1281
 
1308
  return $int_value;
1309
  }
1310
 
1311
+ /**
1312
+ * @param int $length
1313
+ * @param bool $check_buffer
1314
+ *
1315
+ * @return string|false
1316
+ */
1317
  private function readEBMLelementData($length, $check_buffer=false) {
1318
  if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
1319
  return false;
1323
  return $data;
1324
  }
1325
 
1326
+ /**
1327
+ * @param array $element
1328
+ * @param int $parent_end
1329
+ * @param array|bool $get_data
1330
+ *
1331
+ * @return bool
1332
+ */
1333
  private function getEBMLelement(&$element, $parent_end, $get_data=false) {
1334
  if ($this->current_offset >= $parent_end) {
1335
  return false;
1366
  return true;
1367
  }
1368
 
1369
+ /**
1370
+ * @param string $type
1371
+ * @param int $line
1372
+ * @param array $element
1373
+ */
1374
  private function unhandledElement($type, $line, $element) {
1375
  // warn only about unknown and missed elements, not about unuseful
1376
  if (!in_array($element['id'], $this->unuseful_elements)) {
1383
  }
1384
  }
1385
 
1386
+ /**
1387
+ * @param array $SimpleTagArray
1388
+ *
1389
+ * @return bool
1390
+ */
1391
  private function ExtractCommentsSimpleTag($SimpleTagArray) {
1392
  if (!empty($SimpleTagArray['SimpleTag'])) {
1393
  foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
1403
  return true;
1404
  }
1405
 
1406
+ /**
1407
+ * @param int $parent_end
1408
+ *
1409
+ * @return array
1410
+ */
1411
  private function HandleEMBLSimpleTag($parent_end) {
1412
  $simpletag_entry = array();
1413
 
1438
  return $simpletag_entry;
1439
  }
1440
 
1441
+ /**
1442
+ * @param array $element
1443
+ * @param int $block_type
1444
+ * @param array $info
1445
+ *
1446
+ * @return array
1447
+ */
1448
  private function HandleEMBLClusterBlock($element, $block_type, &$info) {
1449
  // http://www.matroska.org/technical/specs/index.html#block_structure
1450
  // http://www.matroska.org/technical/specs/index.html#simpleblock_structure
1508
  return $block_data;
1509
  }
1510
 
1511
+ /**
1512
+ * @param string $EBMLstring
1513
+ *
1514
+ * @return int|float|false
1515
+ */
1516
  private static function EBML2Int($EBMLstring) {
1517
  // http://matroska.org/specs/
1518
 
1555
  return getid3_lib::BigEndian2Int($EBMLstring);
1556
  }
1557
 
1558
+ /**
1559
+ * @param int $EBMLdatestamp
1560
+ *
1561
+ * @return float
1562
+ */
1563
  private static function EBMLdate2unix($EBMLdatestamp) {
1564
  // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
1565
  // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
1566
  return round(($EBMLdatestamp / 1000000000) + 978307200);
1567
  }
1568
 
1569
+ /**
1570
+ * @param int $target_type
1571
+ *
1572
+ * @return string|int
1573
+ */
1574
  public static function TargetTypeValue($target_type) {
1575
  // http://www.matroska.org/technical/specs/tagging/index.html
1576
  static $TargetTypeValue = array();
1586
  return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
1587
  }
1588
 
1589
+ /**
1590
+ * @param int $lacingtype
1591
+ *
1592
+ * @return string|int
1593
+ */
1594
  public static function BlockLacingType($lacingtype) {
1595
  // http://matroska.org/technical/specs/index.html#block_structure
1596
  static $BlockLacingType = array();
1603
  return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
1604
  }
1605
 
1606
+ /**
1607
+ * @param string $codecid
1608
+ *
1609
+ * @return string
1610
+ */
1611
  public static function CodecIDtoCommonName($codecid) {
1612
  // http://www.matroska.org/technical/specs/codecid/index.html
1613
  static $CodecIDlist = array();
1615
  $CodecIDlist['A_AAC'] = 'aac';
1616
  $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac';
1617
  $CodecIDlist['A_AC3'] = 'ac3';
1618
+ $CodecIDlist['A_EAC3'] = 'eac3';
1619
  $CodecIDlist['A_DTS'] = 'dts';
1620
  $CodecIDlist['A_FLAC'] = 'flac';
1621
  $CodecIDlist['A_MPEG/L1'] = 'mp1';
1644
  return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
1645
  }
1646
 
1647
+ /**
1648
+ * @param int $value
1649
+ *
1650
+ * @return string
1651
+ */
1652
  private static function EBMLidName($value) {
1653
  static $EBMLidList = array();
1654
  if (empty($EBMLidList)) {
1847
  return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
1848
  }
1849
 
1850
+ /**
1851
+ * @param int $value
1852
+ *
1853
+ * @return string
1854
+ */
1855
  public static function displayUnit($value) {
1856
  // http://www.matroska.org/technical/specs/index.html#DisplayUnit
1857
  static $units = array(
1863
  return (isset($units[$value]) ? $units[$value] : 'unknown');
1864
  }
1865
 
1866
+ /**
1867
+ * @param array $streams
1868
+ *
1869
+ * @return array
1870
+ */
1871
  private static function getDefaultStreamInfo($streams)
1872
  {
1873
+ $stream = array();
1874
  foreach (array_reverse($streams) as $stream) {
1875
  if ($stream['default']) {
1876
  break;
lib/getid3/module.audio-video.mpeg.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.mpeg.php //
@@ -16,7 +16,8 @@
16
 
17
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
18
 
19
- class getid3_mpeg extends getid3_handler {
 
20
 
21
  const START_CODE_BASE = "\x00\x00\x01";
22
  const VIDEO_PICTURE_START = "\x00\x00\x01\x00";
@@ -28,7 +29,9 @@ class getid3_mpeg extends getid3_handler {
28
  const VIDEO_GROUP_START = "\x00\x00\x01\xB8";
29
  const AUDIO_START = "\x00\x00\x01\xC0";
30
 
31
-
 
 
32
  public function Analyze() {
33
  $info = &$this->getid3->info;
34
 
@@ -87,11 +90,9 @@ class getid3_mpeg extends getid3_handler {
87
  break;
88
 
89
  case 0xB3: // sequence_header_code
90
- /*
91
- Note: purposely doing the less-pretty (and probably a bit slower) method of using string of bits rather than bitwise operations.
92
- Mostly because PHP 32-bit doesn't handle unsigned integers well for bitwise operation.
93
- Also the MPEG stream is designed as a bitstream and often doesn't align nicely with byte boundaries.
94
- */
95
  $info['video']['codec'] = 'MPEG-1'; // will be updated if extension_start_code found
96
 
97
  $bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8));
@@ -122,8 +123,8 @@ class getid3_mpeg extends getid3_handler {
122
  }
123
  }
124
 
125
- $info['mpeg']['video']['pixel_aspect_ratio'] = self::videoAspectRatioLookup($info['mpeg']['video']['raw']['aspect_ratio_information']);
126
- $info['mpeg']['video']['pixel_aspect_ratio_text'] = self::videoAspectRatioTextLookup($info['mpeg']['video']['raw']['aspect_ratio_information']);
127
  $info['mpeg']['video']['frame_rate'] = self::videoFramerateLookup($info['mpeg']['video']['raw']['frame_rate_code']);
128
  if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits = VBR
129
  //$this->warning('This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files');
@@ -169,6 +170,16 @@ class getid3_mpeg extends getid3_handler {
169
  $info['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
170
  $info['mpeg']['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
171
  $info['mpeg']['video']['chroma_format'] = self::chromaFormatTextLookup($info['mpeg']['video']['raw']['chroma_format']);
 
 
 
 
 
 
 
 
 
 
172
  break;
173
 
174
  case 2: // 0010 Sequence Display Extension ID
@@ -258,7 +269,7 @@ class getid3_mpeg extends getid3_handler {
258
 
259
  case 0xB8: // group_of_pictures_header
260
  $GOPcounter++;
261
- if ($info['mpeg']['video']['bitrate_mode'] == 'vbr') {
262
  $bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4)); // 27 bits needed for group_of_pictures_header
263
  $bitstreamoffset = 0;
264
 
@@ -274,7 +285,7 @@ class getid3_mpeg extends getid3_handler {
274
  $GOPheader['closed_gop'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: closed_gop
275
  $GOPheader['broken_link'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: broken_link
276
 
277
- $time_code_separator = ($GOPheader['drop_frame_flag'] ? ';' : ':'); // While non-drop time code is displayed with colons separating the digit pairs"HH:MM:SS:FF"drop frame is usually represented with a semi-colon (;) or period (.) as the divider between all the digit pairs"HH;MM;SS;FF", "HH.MM.SS.FF"
278
  $GOPheader['time_code'] = sprintf('%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d', $GOPheader['time_code_hours'], $GOPheader['time_code_minutes'], $GOPheader['time_code_seconds'], $GOPheader['time_code_pictures']);
279
 
280
  $info['mpeg']['group_of_pictures'][] = $GOPheader;
@@ -459,7 +470,7 @@ $PackedElementaryStream['additional_header_bytes'] = $additional_header_bytes;
459
  // // break;
460
  // //}
461
  // //$info['playtime_seconds'] *= $multiplier;
462
- // //$info['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.';
463
  // if ($info['video']['bitrate'] < 50000) {
464
  // $this->warning('Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.');
465
  // }
@@ -502,6 +513,14 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
502
  return true;
503
  }
504
 
 
 
 
 
 
 
 
 
505
  private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean=true) {
506
  $return = bindec(substr($bitstream, $bitstreamoffset, $bits_to_read));
507
  $bitstreamoffset += $bits_to_read;
@@ -511,7 +530,12 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
511
  return $return;
512
  }
513
 
514
-
 
 
 
 
 
515
  public static function systemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
516
  $OverheadPercentage = 0;
517
 
@@ -563,44 +587,93 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
563
  return $OverheadPercentage;
564
  }
565
 
566
-
 
 
 
 
567
  public static function videoFramerateLookup($rawframerate) {
568
  $lookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
569
- return (isset($lookup[$rawframerate]) ? (float) $lookup[$rawframerate] : (float) 0);
570
  }
571
 
572
- public static function videoAspectRatioLookup($rawaspectratio) {
573
- $lookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0);
574
- return (isset($lookup[$rawaspectratio]) ? (float) $lookup[$rawaspectratio] : (float) 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
575
  }
576
 
577
- public static function videoAspectRatioTextLookup($rawaspectratio) {
578
- $lookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved');
579
- return (isset($lookup[$rawaspectratio]) ? $lookup[$rawaspectratio] : '');
 
 
 
 
 
 
 
 
 
580
  }
581
 
 
 
 
 
 
582
  public static function videoFormatTextLookup($video_format) {
583
  // ISO/IEC 13818-2, section 6.3.6, Table 6-6. Meaning of video_format
584
  $lookup = array('component', 'PAL', 'NTSC', 'SECAM', 'MAC', 'Unspecified video format', 'reserved(6)', 'reserved(7)');
585
  return (isset($lookup[$video_format]) ? $lookup[$video_format] : '');
586
  }
587
 
 
 
 
 
 
588
  public static function scalableModeTextLookup($scalable_mode) {
589
  // ISO/IEC 13818-2, section 6.3.8, Table 6-10. Definition of scalable_mode
590
  $lookup = array('data partitioning', 'spatial scalability', 'SNR scalability', 'temporal scalability');
591
  return (isset($lookup[$scalable_mode]) ? $lookup[$scalable_mode] : '');
592
  }
593
 
 
 
 
 
 
594
  public static function pictureStructureTextLookup($picture_structure) {
595
  // ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
596
  $lookup = array('reserved', 'Top Field', 'Bottom Field', 'Frame picture');
597
  return (isset($lookup[$picture_structure]) ? $lookup[$picture_structure] : '');
598
  }
599
 
 
 
 
 
 
600
  public static function chromaFormatTextLookup($chroma_format) {
601
  // ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
602
  $lookup = array('reserved', '4:2:0', '4:2:2', '4:4:4');
603
  return (isset($lookup[$chroma_format]) ? $lookup[$chroma_format] : '');
604
  }
605
 
606
- }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.mpeg.php //
16
 
17
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
18
 
19
+ class getid3_mpeg extends getid3_handler
20
+ {
21
 
22
  const START_CODE_BASE = "\x00\x00\x01";
23
  const VIDEO_PICTURE_START = "\x00\x00\x01\x00";
29
  const VIDEO_GROUP_START = "\x00\x00\x01\xB8";
30
  const AUDIO_START = "\x00\x00\x01\xC0";
31
 
32
+ /**
33
+ * @return bool
34
+ */
35
  public function Analyze() {
36
  $info = &$this->getid3->info;
37
 
90
  break;
91
 
92
  case 0xB3: // sequence_header_code
93
+ // Note: purposely doing the less-pretty (and probably a bit slower) method of using string of bits rather than bitwise operations.
94
+ // Mostly because PHP 32-bit doesn't handle unsigned integers well for bitwise operation.
95
+ // Also the MPEG stream is designed as a bitstream and often doesn't align nicely with byte boundaries.
 
 
96
  $info['video']['codec'] = 'MPEG-1'; // will be updated if extension_start_code found
97
 
98
  $bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8));
123
  }
124
  }
125
 
126
+ $info['mpeg']['video']['pixel_aspect_ratio'] = self::videoAspectRatioLookup($info['mpeg']['video']['raw']['aspect_ratio_information']); // may be overridden later if file turns out to be MPEG-2
127
+ $info['mpeg']['video']['pixel_aspect_ratio_text'] = self::videoAspectRatioTextLookup($info['mpeg']['video']['raw']['aspect_ratio_information']); // may be overridden later if file turns out to be MPEG-2
128
  $info['mpeg']['video']['frame_rate'] = self::videoFramerateLookup($info['mpeg']['video']['raw']['frame_rate_code']);
129
  if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits = VBR
130
  //$this->warning('This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files');
170
  $info['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
171
  $info['mpeg']['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
172
  $info['mpeg']['video']['chroma_format'] = self::chromaFormatTextLookup($info['mpeg']['video']['raw']['chroma_format']);
173
+
174
+ if (isset($info['mpeg']['video']['raw']['aspect_ratio_information'])) {
175
+ // MPEG-2 defines the aspect ratio flag differently from MPEG-1, but the MPEG-2 extension start code may occur after we've already looked up the aspect ratio assuming it was MPEG-1, so re-lookup assuming MPEG-2
176
+ // This must be done after the extended size is known, so the display aspect ratios can be converted to pixel aspect ratios.
177
+ $info['mpeg']['video']['pixel_aspect_ratio'] = self::videoAspectRatioLookup($info['mpeg']['video']['raw']['aspect_ratio_information'], 2, $info['video']['resolution_x'], $info['video']['resolution_y']);
178
+ $info['mpeg']['video']['pixel_aspect_ratio_text'] = self::videoAspectRatioTextLookup($info['mpeg']['video']['raw']['aspect_ratio_information'], 2);
179
+ $info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio'];
180
+ $info['video']['pixel_aspect_ratio_text'] = $info['mpeg']['video']['pixel_aspect_ratio_text'];
181
+ }
182
+
183
  break;
184
 
185
  case 2: // 0010 Sequence Display Extension ID
269
 
270
  case 0xB8: // group_of_pictures_header
271
  $GOPcounter++;
272
+ if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
273
  $bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4)); // 27 bits needed for group_of_pictures_header
274
  $bitstreamoffset = 0;
275
 
285
  $GOPheader['closed_gop'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: closed_gop
286
  $GOPheader['broken_link'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: broken_link
287
 
288
+ $time_code_separator = ($GOPheader['drop_frame_flag'] ? ';' : ':'); // While non-drop time code is displayed with colons separating the digit pairs "HH:MM:SS:FF" drop frame is usually represented with a semi-colon (;) or period (.) as the divider between all the digit pairs "HH;MM;SS;FF", "HH.MM.SS.FF"
289
  $GOPheader['time_code'] = sprintf('%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d', $GOPheader['time_code_hours'], $GOPheader['time_code_minutes'], $GOPheader['time_code_seconds'], $GOPheader['time_code_pictures']);
290
 
291
  $info['mpeg']['group_of_pictures'][] = $GOPheader;
470
  // // break;
471
  // //}
472
  // //$info['playtime_seconds'] *= $multiplier;
473
+ // //$this->warning('Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.');
474
  // if ($info['video']['bitrate'] < 50000) {
475
  // $this->warning('Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.');
476
  // }
513
  return true;
514
  }
515
 
516
+ /**
517
+ * @param string $bitstream
518
+ * @param int $bitstreamoffset
519
+ * @param int $bits_to_read
520
+ * @param bool $return_singlebit_as_boolean
521
+ *
522
+ * @return bool|float|int
523
+ */
524
  private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean=true) {
525
  $return = bindec(substr($bitstream, $bitstreamoffset, $bits_to_read));
526
  $bitstreamoffset += $bits_to_read;
530
  return $return;
531
  }
532
 
533
+ /**
534
+ * @param int $VideoBitrate
535
+ * @param int $AudioBitrate
536
+ *
537
+ * @return float|int
538
+ */
539
  public static function systemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
540
  $OverheadPercentage = 0;
541
 
587
  return $OverheadPercentage;
588
  }
589
 
590
+ /**
591
+ * @param int $rawframerate
592
+ *
593
+ * @return float
594
+ */
595
  public static function videoFramerateLookup($rawframerate) {
596
  $lookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
597
+ return (float) (isset($lookup[$rawframerate]) ? $lookup[$rawframerate] : 0);
598
  }
599
 
600
+ /**
601
+ * @param int $rawaspectratio
602
+ * @param int $mpeg_version
603
+ * @param int $width
604
+ * @param int $height
605
+ *
606
+ * @return float
607
+ */
608
+ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, $width=0, $height=0) {
609
+ $lookup = array(
610
+ 1 => array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0),
611
+ 2 => array(0, 1, 1.3333, 1.7778, 2.2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
612
+ );
613
+ $ratio = (float) (isset($lookup[$mpeg_version][$rawaspectratio]) ? $lookup[$mpeg_version][$rawaspectratio] : 0);
614
+ if ($mpeg_version == 2 && $ratio != 1) {
615
+ // Calculate pixel aspect ratio from MPEG-2 display aspect ratio
616
+ $ratio = $ratio * $height / $width;
617
+ }
618
+ return $ratio;
619
  }
620
 
621
+ /**
622
+ * @param int $rawaspectratio
623
+ * @param int $mpeg_version
624
+ *
625
+ * @return string
626
+ */
627
+ public static function videoAspectRatioTextLookup($rawaspectratio, $mpeg_version=1) {
628
+ $lookup = array(
629
+ 1 => array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved'),
630
+ 2 => array('forbidden', 'square pixels', '4:3', '16:9', '2.21:1', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved'), // http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html
631
+ );
632
+ return (isset($lookup[$mpeg_version][$rawaspectratio]) ? $lookup[$mpeg_version][$rawaspectratio] : '');
633
  }
634
 
635
+ /**
636
+ * @param int $video_format
637
+ *
638
+ * @return string
639
+ */
640
  public static function videoFormatTextLookup($video_format) {
641
  // ISO/IEC 13818-2, section 6.3.6, Table 6-6. Meaning of video_format
642
  $lookup = array('component', 'PAL', 'NTSC', 'SECAM', 'MAC', 'Unspecified video format', 'reserved(6)', 'reserved(7)');
643
  return (isset($lookup[$video_format]) ? $lookup[$video_format] : '');
644
  }
645
 
646
+ /**
647
+ * @param int $scalable_mode
648
+ *
649
+ * @return string
650
+ */
651
  public static function scalableModeTextLookup($scalable_mode) {
652
  // ISO/IEC 13818-2, section 6.3.8, Table 6-10. Definition of scalable_mode
653
  $lookup = array('data partitioning', 'spatial scalability', 'SNR scalability', 'temporal scalability');
654
  return (isset($lookup[$scalable_mode]) ? $lookup[$scalable_mode] : '');
655
  }
656
 
657
+ /**
658
+ * @param int $picture_structure
659
+ *
660
+ * @return string
661
+ */
662
  public static function pictureStructureTextLookup($picture_structure) {
663
  // ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
664
  $lookup = array('reserved', 'Top Field', 'Bottom Field', 'Frame picture');
665
  return (isset($lookup[$picture_structure]) ? $lookup[$picture_structure] : '');
666
  }
667
 
668
+ /**
669
+ * @param int $chroma_format
670
+ *
671
+ * @return string
672
+ */
673
  public static function chromaFormatTextLookup($chroma_format) {
674
  // ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
675
  $lookup = array('reserved', '4:2:0', '4:2:2', '4:4:4');
676
  return (isset($lookup[$chroma_format]) ? $lookup[$chroma_format] : '');
677
  }
678
 
679
+ }
lib/getid3/module.audio-video.nsv.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.nsv.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_nsv extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -47,18 +49,23 @@ class getid3_nsv extends getid3_handler
47
  break;
48
 
49
  default:
50
- $info['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"';
51
  return false;
52
  break;
53
  }
54
 
55
  if (!isset($info['nsv']['NSVf'])) {
56
- $info['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate';
57
  }
58
 
59
  return true;
60
  }
61
 
 
 
 
 
 
62
  public function getNSVsHeaderFilepointer($fileoffset) {
63
  $info = &$this->getid3->info;
64
  $this->fseek($fileoffset);
@@ -69,7 +76,7 @@ class getid3_nsv extends getid3_handler
69
  $offset += 4;
70
 
71
  if ($info['nsv']['NSVs']['identifier'] != 'NSVs') {
72
- $info['error'][] = 'expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead';
73
  unset($info['nsv']['NSVs']);
74
  return false;
75
  }
@@ -132,6 +139,12 @@ class getid3_nsv extends getid3_handler
132
  return true;
133
  }
134
 
 
 
 
 
 
 
135
  public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) {
136
  $info = &$this->getid3->info;
137
  $this->fseek($fileoffset);
@@ -142,7 +155,7 @@ class getid3_nsv extends getid3_handler
142
  $offset += 4;
143
 
144
  if ($info['nsv']['NSVf']['identifier'] != 'NSVf') {
145
- $info['error'][] = 'expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead';
146
  unset($info['nsv']['NSVf']);
147
  return false;
148
  }
@@ -155,7 +168,7 @@ class getid3_nsv extends getid3_handler
155
  $offset += 4;
156
 
157
  if ($info['nsv']['NSVf']['file_size'] > $info['avdataend']) {
158
- $info['warning'][] = 'truncated file - NSVf header indicates '.$info['nsv']['NSVf']['file_size'].' bytes, file actually '.$info['avdataend'].' bytes';
159
  }
160
 
161
  $info['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
@@ -168,7 +181,7 @@ class getid3_nsv extends getid3_handler
168
  $offset += 4;
169
 
170
  if ($info['nsv']['NSVf']['playtime_ms'] == 0) {
171
- $info['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero';
172
  return false;
173
  }
174
 
@@ -205,18 +218,22 @@ class getid3_nsv extends getid3_handler
205
  return true;
206
  }
207
 
208
-
 
 
 
 
209
  public static function NSVframerateLookup($framerateindex) {
210
  if ($framerateindex <= 127) {
211
  return (float) $framerateindex;
212
  }
213
  static $NSVframerateLookup = array();
214
  if (empty($NSVframerateLookup)) {
215
- $NSVframerateLookup[129] = (float) 29.970;
216
- $NSVframerateLookup[131] = (float) 23.976;
217
- $NSVframerateLookup[133] = (float) 14.985;
218
- $NSVframerateLookup[197] = (float) 59.940;
219
- $NSVframerateLookup[199] = (float) 47.952;
220
  }
221
  return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false);
222
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.nsv.php //
17
 
18
  class getid3_nsv extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
49
  break;
50
 
51
  default:
52
+ $this->error('Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"');
53
  return false;
54
  break;
55
  }
56
 
57
  if (!isset($info['nsv']['NSVf'])) {
58
+ $this->warning('NSVf header not present - cannot calculate playtime or bitrate');
59
  }
60
 
61
  return true;
62
  }
63
 
64
+ /**
65
+ * @param int $fileoffset
66
+ *
67
+ * @return bool
68
+ */
69
  public function getNSVsHeaderFilepointer($fileoffset) {
70
  $info = &$this->getid3->info;
71
  $this->fseek($fileoffset);
76
  $offset += 4;
77
 
78
  if ($info['nsv']['NSVs']['identifier'] != 'NSVs') {
79
+ $this->error('expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead');
80
  unset($info['nsv']['NSVs']);
81
  return false;
82
  }
139
  return true;
140
  }
141
 
142
+ /**
143
+ * @param int $fileoffset
144
+ * @param bool $getTOCoffsets
145
+ *
146
+ * @return bool
147
+ */
148
  public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) {
149
  $info = &$this->getid3->info;
150
  $this->fseek($fileoffset);
155
  $offset += 4;
156
 
157
  if ($info['nsv']['NSVf']['identifier'] != 'NSVf') {
158
+ $this->error('expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead');
159
  unset($info['nsv']['NSVf']);
160
  return false;
161
  }
168
  $offset += 4;
169
 
170
  if ($info['nsv']['NSVf']['file_size'] > $info['avdataend']) {
171
+ $this->warning('truncated file - NSVf header indicates '.$info['nsv']['NSVf']['file_size'].' bytes, file actually '.$info['avdataend'].' bytes');
172
  }
173
 
174
  $info['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
181
  $offset += 4;
182
 
183
  if ($info['nsv']['NSVf']['playtime_ms'] == 0) {
184
+ $this->error('Corrupt NSV file: NSVf.playtime_ms == zero');
185
  return false;
186
  }
187
 
218
  return true;
219
  }
220
 
221
+ /**
222
+ * @param int $framerateindex
223
+ *
224
+ * @return float|false
225
+ */
226
  public static function NSVframerateLookup($framerateindex) {
227
  if ($framerateindex <= 127) {
228
  return (float) $framerateindex;
229
  }
230
  static $NSVframerateLookup = array();
231
  if (empty($NSVframerateLookup)) {
232
+ $NSVframerateLookup[129] = 29.970;
233
+ $NSVframerateLookup[131] = 23.976;
234
+ $NSVframerateLookup[133] = 14.985;
235
+ $NSVframerateLookup[197] = 59.940;
236
+ $NSVframerateLookup[199] = 47.952;
237
  }
238
  return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false);
239
  }
lib/getid3/module.audio-video.quicktime.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.quicktime.php //
@@ -24,6 +24,9 @@ class getid3_quicktime extends getid3_handler
24
  public $ReturnAtomData = true;
25
  public $ParseAllPossibleAtoms = false;
26
 
 
 
 
27
  public function Analyze() {
28
  $info = &$this->getid3->info;
29
 
@@ -35,10 +38,10 @@ class getid3_quicktime extends getid3_handler
35
 
36
  $offset = 0;
37
  $atomcounter = 0;
38
- $atom_data_read_buffer_size = ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 2) : $this->getid3->option_fread_buffer_size * 1024); // allow [default: 32MB] if PHP configured with no memory_limit
39
  while ($offset < $info['avdataend']) {
40
  if (!getid3_lib::intValueSupported($offset)) {
41
- $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
42
  break;
43
  }
44
  $this->fseek($offset);
@@ -57,7 +60,7 @@ class getid3_quicktime extends getid3_handler
57
  $info['quicktime'][$atomname]['offset'] = $offset;
58
 
59
  if (($offset + $atomsize) > $info['avdataend']) {
60
- $info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';
61
  return false;
62
  }
63
 
@@ -81,12 +84,90 @@ class getid3_quicktime extends getid3_handler
81
  unset($info['avdataend_tmp']);
82
  }
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
85
  $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
86
  }
87
  if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
88
  $info['audio']['bitrate'] = $info['bitrate'];
89
  }
 
 
 
90
  if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
91
  foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
92
  $samples_per_second = $samples_count / $info['playtime_seconds'];
@@ -98,10 +179,14 @@ class getid3_quicktime extends getid3_handler
98
  }
99
  }
100
  }
101
- if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {
102
  $info['fileformat'] = 'mp4';
103
- $info['mime_type'] = 'audio/mp4';
104
- unset($info['video']['dataformat']);
 
 
 
 
105
  }
106
 
107
  if (!$this->ReturnAtomData) {
@@ -114,1344 +199,1667 @@ class getid3_quicktime extends getid3_handler
114
  if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
115
  $info['video']['dataformat'] = 'quicktime';
116
  }
 
 
 
117
 
118
  return true;
119
  }
120
 
 
 
 
 
 
 
 
 
 
 
121
  public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
122
  // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
123
  // https://code.google.com/p/mp4v2/wiki/iTunesMetadata
124
 
125
  $info = &$this->getid3->info;
126
 
127
- $atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see http://www.getid3.org/phpBB3/viewtopic.php?t=1717
128
  array_push($atomHierarchy, $atomname);
129
  $atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
130
  $atom_structure['name'] = $atomname;
131
  $atom_structure['size'] = $atomsize;
132
  $atom_structure['offset'] = $baseoffset;
133
- switch ($atomname) {
134
- case 'moov': // MOVie container atom
135
- case 'trak': // TRAcK container atom
136
- case 'clip': // CLIPping container atom
137
- case 'matt': // track MATTe container atom
138
- case 'edts': // EDiTS container atom
139
- case 'tref': // Track REFerence container atom
140
- case 'mdia': // MeDIA container atom
141
- case 'minf': // Media INFormation container atom
142
- case 'dinf': // Data INFormation container atom
143
- case 'udta': // User DaTA container atom
144
- case 'cmov': // Compressed MOVie container atom
145
- case 'rmra': // Reference Movie Record Atom
146
- case 'rmda': // Reference Movie Descriptor Atom
147
- case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
148
- $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
149
- break;
 
 
 
 
 
 
150
 
151
- case 'ilst': // Item LiST container atom
152
- if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
153
- // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
154
- $allnumericnames = true;
155
- foreach ($atom_structure['subatoms'] as $subatomarray) {
156
- if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
157
- $allnumericnames = false;
158
- break;
159
- }
160
- }
161
- if ($allnumericnames) {
162
- $newData = array();
163
  foreach ($atom_structure['subatoms'] as $subatomarray) {
164
- foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
165
- unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
166
- $newData[$subatomarray['name']] = $newData_subatomarray;
167
  break;
168
  }
169
  }
170
- $atom_structure['data'] = $newData;
171
- unset($atom_structure['subatoms']);
 
 
 
 
 
 
 
 
 
 
172
  }
173
- }
174
- break;
175
-
176
- case "\x00\x00\x00\x01":
177
- case "\x00\x00\x00\x02":
178
- case "\x00\x00\x00\x03":
179
- case "\x00\x00\x00\x04":
180
- case "\x00\x00\x00\x05":
181
- $atomname = getid3_lib::BigEndian2Int($atomname);
182
- $atom_structure['name'] = $atomname;
183
- $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
184
- break;
185
 
186
- case 'stbl': // Sample TaBLe container atom
187
- $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
188
- $isVideo = false;
189
- $framerate = 0;
190
- $framecount = 0;
191
- foreach ($atom_structure['subatoms'] as $key => $value_array) {
192
- if (isset($value_array['sample_description_table'])) {
193
- foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
194
- if (isset($value_array2['data_format'])) {
195
- switch ($value_array2['data_format']) {
196
- case 'avc1':
197
- case 'mp4v':
198
- // video data
199
- $isVideo = true;
200
- break;
201
- case 'mp4a':
202
- // audio data
203
- break;
 
204
  }
205
  }
206
- }
207
- } elseif (isset($value_array['time_to_sample_table'])) {
208
- foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
209
- if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
210
- $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
211
- $framecount = $value_array2['sample_count'];
212
  }
213
  }
214
  }
215
- }
216
- if ($isVideo && $framerate) {
217
- $info['quicktime']['video']['frame_rate'] = $framerate;
218
- $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
219
- }
220
- if ($isVideo && $framecount) {
221
- $info['quicktime']['video']['frame_count'] = $framecount;
222
- }
223
- break;
224
-
225
 
226
- case "\xA9".'alb': // ALBum
227
- case "\xA9".'ART': //
228
- case "\xA9".'art': // ARTist
229
- case "\xA9".'aut': //
230
- case "\xA9".'cmt': // CoMmenT
231
- case "\xA9".'com': // COMposer
232
- case "\xA9".'cpy': //
233
- case "\xA9".'day': // content created year
234
- case "\xA9".'dir': //
235
- case "\xA9".'ed1': //
236
- case "\xA9".'ed2': //
237
- case "\xA9".'ed3': //
238
- case "\xA9".'ed4': //
239
- case "\xA9".'ed5': //
240
- case "\xA9".'ed6': //
241
- case "\xA9".'ed7': //
242
- case "\xA9".'ed8': //
243
- case "\xA9".'ed9': //
244
- case "\xA9".'enc': //
245
- case "\xA9".'fmt': //
246
- case "\xA9".'gen': // GENre
247
- case "\xA9".'grp': // GRouPing
248
- case "\xA9".'hst': //
249
- case "\xA9".'inf': //
250
- case "\xA9".'lyr': // LYRics
251
- case "\xA9".'mak': //
252
- case "\xA9".'mod': //
253
- case "\xA9".'nam': // full NAMe
254
- case "\xA9".'ope': //
255
- case "\xA9".'PRD': //
256
- case "\xA9".'prf': //
257
- case "\xA9".'req': //
258
- case "\xA9".'src': //
259
- case "\xA9".'swr': //
260
- case "\xA9".'too': // encoder
261
- case "\xA9".'trk': // TRacK
262
- case "\xA9".'url': //
263
- case "\xA9".'wrn': //
264
- case "\xA9".'wrt': // WRiTer
265
- case '----': // itunes specific
266
- case 'aART': // Album ARTist
267
- case 'akID': // iTunes store account type
268
- case 'apID': // Purchase Account
269
- case 'atID': //
270
- case 'catg': // CaTeGory
271
- case 'cmID': //
272
- case 'cnID': //
273
- case 'covr': // COVeR artwork
274
- case 'cpil': // ComPILation
275
- case 'cprt': // CoPyRighT
276
- case 'desc': // DESCription
277
- case 'disk': // DISK number
278
- case 'egid': // Episode Global ID
279
- case 'geID': //
280
- case 'gnre': // GeNRE
281
- case 'hdvd': // HD ViDeo
282
- case 'keyw': // KEYWord
283
- case 'ldes': // Long DEScription
284
- case 'pcst': // PodCaST
285
- case 'pgap': // GAPless Playback
286
- case 'plID': //
287
- case 'purd': // PURchase Date
288
- case 'purl': // Podcast URL
289
- case 'rati': //
290
- case 'rndu': //
291
- case 'rpdu': //
292
- case 'rtng': // RaTiNG
293
- case 'sfID': // iTunes store country
294
- case 'soaa': // SOrt Album Artist
295
- case 'soal': // SOrt ALbum
296
- case 'soar': // SOrt ARtist
297
- case 'soco': // SOrt COmposer
298
- case 'sonm': // SOrt NaMe
299
- case 'sosn': // SOrt Show Name
300
- case 'stik': //
301
- case 'tmpo': // TeMPO (BPM)
302
- case 'trkn': // TRacK Number
303
- case 'tven': // tvEpisodeID
304
- case 'tves': // TV EpiSode
305
- case 'tvnn': // TV Network Name
306
- case 'tvsh': // TV SHow Name
307
- case 'tvsn': // TV SeasoN
308
- if ($atom_parent == 'udta') {
309
- // User data atom handler
310
- $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
311
- $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
312
- $atom_structure['data'] = substr($atom_data, 4);
313
 
314
- $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
315
- if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
316
- $info['comments']['language'][] = $atom_structure['language'];
317
- }
318
- } else {
319
- // Apple item list box atom handler
320
- $atomoffset = 0;
321
- if (substr($atom_data, 2, 2) == "\x10\xB5") {
322
- // not sure what it means, but observed on iPhone4 data.
323
- // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
324
- while ($atomoffset < strlen($atom_data)) {
325
- $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2));
326
- $boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
327
- $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
328
- if ($boxsmallsize <= 1) {
329
- $info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
330
- $atom_structure['data'] = null;
331
- $atomoffset = strlen($atom_data);
332
- break;
333
- }
334
- switch ($boxsmalltype) {
335
- case "\x10\xB5":
336
- $atom_structure['data'] = $boxsmalldata;
337
- break;
338
- default:
339
- $info['warning'][] = 'Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset;
340
- $atom_structure['data'] = $atom_data;
341
- break;
342
- }
343
- $atomoffset += (4 + $boxsmallsize);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  }
345
  } else {
346
- while ($atomoffset < strlen($atom_data)) {
347
- $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
348
- $boxtype = substr($atom_data, $atomoffset + 4, 4);
349
- $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
350
- if ($boxsize <= 1) {
351
- $info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
352
- $atom_structure['data'] = null;
353
- $atomoffset = strlen($atom_data);
354
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  }
356
- $atomoffset += $boxsize;
357
-
358
- switch ($boxtype) {
359
- case 'mean':
360
- case 'name':
361
- $atom_structure[$boxtype] = substr($boxdata, 4);
 
 
 
362
  break;
 
 
363
 
364
- case 'data':
365
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1));
366
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3));
367
- switch ($atom_structure['flags_raw']) {
368
- case 0: // data flag
369
- case 21: // tmpo/cpil flag
370
- switch ($atomname) {
371
- case 'cpil':
372
- case 'hdvd':
373
- case 'pcst':
374
- case 'pgap':
375
- // 8-bit integer (boolean)
376
- $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
377
- break;
378
-
379
- case 'tmpo':
380
- // 16-bit integer
381
- $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
382
- break;
383
-
384
- case 'disk':
385
- case 'trkn':
386
- // binary
387
- $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
388
- $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
389
- $atom_structure['data'] = empty($num) ? '' : $num;
390
- $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
391
- break;
392
-
393
- case 'gnre':
394
- // enum
395
- $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
396
- $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
397
- break;
398
-
399
- case 'rtng':
400
- // 8-bit integer
401
- $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
402
- $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
403
- break;
404
-
405
- case 'stik':
406
- // 8-bit integer (enum)
407
- $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
408
- $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
409
- break;
410
-
411
- case 'sfID':
412
- // 32-bit integer
413
- $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
414
- $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
415
- break;
416
-
417
- case 'egid':
418
- case 'purl':
419
- $atom_structure['data'] = substr($boxdata, 8);
420
- break;
421
-
422
- case 'plID':
423
- // 64-bit integer
424
- $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));
425
-
426
- case 'atID':
427
- case 'cnID':
428
- case 'geID':
429
- case 'tves':
430
- case 'tvsn':
431
- default:
432
- // 32-bit integer
433
- $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
434
- }
435
- break;
436
 
437
- case 1: // text flag
438
- case 13: // image flag
439
- default:
440
- $atom_structure['data'] = substr($boxdata, 8);
441
- if ($atomname == 'covr') {
442
- // not a foolproof check, but better than nothing
443
- if (preg_match('#^\xFF\xD8\xFF#', $atom_structure['data'])) {
444
- $atom_structure['image_mime'] = 'image/jpeg';
445
- } elseif (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $atom_structure['data'])) {
446
- $atom_structure['image_mime'] = 'image/png';
447
- } elseif (preg_match('#^GIF#', $atom_structure['data'])) {
448
- $atom_structure['image_mime'] = 'image/gif';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  }
450
- }
451
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
 
453
- }
454
- break;
455
 
456
- default:
457
- $info['warning'][] = 'Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset;
458
- $atom_structure['data'] = $atom_data;
459
 
 
460
  }
461
  }
462
  }
463
- }
464
- $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
465
- break;
466
 
467
 
468
- case 'play': // auto-PLAY atom
469
- $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
470
 
471
- $info['quicktime']['autoplay'] = $atom_structure['autoplay'];
472
- break;
473
 
474
 
475
- case 'WLOC': // Window LOCation atom
476
- $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
477
- $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
478
- break;
479
 
480
 
481
- case 'LOOP': // LOOPing atom
482
- case 'SelO': // play SELection Only atom
483
- case 'AllF': // play ALL Frames atom
484
- $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
485
- break;
486
 
487
 
488
- case 'name': //
489
- case 'MCPS': // Media Cleaner PRo
490
- case '@PRM': // adobe PReMiere version
491
- case '@PRQ': // adobe PRemiere Quicktime version
492
- $atom_structure['data'] = $atom_data;
493
- break;
494
 
495
 
496
- case 'cmvd': // Compressed MooV Data atom
497
- // Code by ubergeekØubergeek*tv based on information from
498
- // http://developer.apple.com/quicktime/icefloe/dispatch012.html
499
- $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
500
 
501
- $CompressedFileData = substr($atom_data, 4);
502
- if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
503
- $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
504
- } else {
505
- $info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];
506
- }
507
- break;
508
 
509
 
510
- case 'dcom': // Data COMpression atom
511
- $atom_structure['compression_id'] = $atom_data;
512
- $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
513
- break;
514
 
515
 
516
- case 'rdrf': // Reference movie Data ReFerence atom
517
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
518
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
519
- $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
520
 
521
- $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);
522
- $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
523
- switch ($atom_structure['reference_type_name']) {
524
- case 'url ':
525
- $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));
526
- break;
527
 
528
- case 'alis':
529
- $atom_structure['file_alias'] = substr($atom_data, 12);
530
- break;
531
 
532
- case 'rsrc':
533
- $atom_structure['resource_alias'] = substr($atom_data, 12);
534
- break;
535
 
536
- default:
537
- $atom_structure['data'] = substr($atom_data, 12);
538
- break;
539
- }
540
- break;
541
 
542
 
543
- case 'rmqu': // Reference Movie QUality atom
544
- $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
545
- break;
546
 
547
 
548
- case 'rmcs': // Reference Movie Cpu Speed atom
549
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
550
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
551
- $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
552
- break;
553
 
554
 
555
- case 'rmvc': // Reference Movie Version Check atom
556
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
557
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
558
- $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);
559
- $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
560
- $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
561
- $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
562
- break;
563
 
564
 
565
- case 'rmcd': // Reference Movie Component check atom
566
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
567
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
568
- $atom_structure['component_type'] = substr($atom_data, 4, 4);
569
- $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
570
- $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
571
- $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
572
- $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
573
- $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
574
- break;
575
 
576
 
577
- case 'rmdr': // Reference Movie Data Rate atom
578
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
579
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
580
- $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
581
 
582
- $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
583
- break;
584
 
585
 
586
- case 'rmla': // Reference Movie Language Atom
587
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
588
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
589
- $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
590
 
591
- $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
592
- if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
593
- $info['comments']['language'][] = $atom_structure['language'];
594
- }
595
- break;
596
 
597
 
598
- case 'rmla': // Reference Movie Language Atom
599
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
600
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
601
- $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
602
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
 
604
 
605
- case 'ptv ': // Print To Video - defines a movie's full screen mode
606
- // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
607
- $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
608
- $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
609
- $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
610
- $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
611
- $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
612
-
613
- $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
614
- $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
615
-
616
- $ptv_lookup[0] = 'normal';
617
- $ptv_lookup[1] = 'double';
618
- $ptv_lookup[2] = 'half';
619
- $ptv_lookup[3] = 'full';
620
- $ptv_lookup[4] = 'current';
621
- if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
622
- $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
623
- } else {
624
- $info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';
625
- }
626
- break;
627
 
 
 
 
 
 
 
 
 
 
 
 
 
628
 
629
- case 'stsd': // Sample Table Sample Description atom
630
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
631
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
632
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
633
- $stsdEntriesDataOffset = 8;
634
- for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
635
- $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
636
- $stsdEntriesDataOffset += 4;
637
- $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4);
638
- $stsdEntriesDataOffset += 4;
639
- $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
640
- $stsdEntriesDataOffset += 6;
641
- $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
642
- $stsdEntriesDataOffset += 2;
643
- $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
644
- $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
645
-
646
- $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
647
- $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
648
- $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
649
-
650
- switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
651
-
652
- case "\x00\x00\x00\x00":
653
- // audio tracks
654
- $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
655
- $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2));
656
- $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2));
657
- $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2));
658
- $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4));
659
-
660
- // video tracks
661
- // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
662
- $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
663
- $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
664
- $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
665
- $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
666
- $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
667
- $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
668
- $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4));
669
- $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2));
670
- $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4);
671
- $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2));
672
- $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2));
673
-
674
- switch ($atom_structure['sample_description_table'][$i]['data_format']) {
675
- case '2vuY':
676
- case 'avc1':
677
- case 'cvid':
678
- case 'dvc ':
679
- case 'dvcp':
680
- case 'gif ':
681
- case 'h263':
682
- case 'jpeg':
683
- case 'kpcd':
684
- case 'mjpa':
685
- case 'mjpb':
686
- case 'mp4v':
687
- case 'png ':
688
- case 'raw ':
689
- case 'rle ':
690
- case 'rpza':
691
- case 'smc ':
692
- case 'SVQ1':
693
- case 'SVQ3':
694
- case 'tiff':
695
- case 'v210':
696
- case 'v216':
697
- case 'v308':
698
- case 'v408':
699
- case 'v410':
700
- case 'yuv2':
701
- $info['fileformat'] = 'mp4';
702
- $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
703
- // http://www.getid3.org/phpBB3/viewtopic.php?t=1550
704
- //if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
705
- if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
706
- // assume that values stored here are more important than values stored in [tkhd] atom
707
- $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
708
- $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
709
- $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
710
- $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
711
- }
712
- break;
713
 
714
- case 'qtvr':
715
- $info['video']['dataformat'] = 'quicktimevr';
716
- break;
717
 
718
- case 'mp4a':
719
- default:
720
- $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
721
- $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
722
- $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels'];
723
- $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
724
- $info['audio']['codec'] = $info['quicktime']['audio']['codec'];
725
- $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate'];
726
- $info['audio']['channels'] = $info['quicktime']['audio']['channels'];
727
- $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth'];
728
- switch ($atom_structure['sample_description_table'][$i]['data_format']) {
729
- case 'raw ': // PCM
730
- case 'alac': // Apple Lossless Audio Codec
731
- $info['audio']['lossless'] = true;
732
- break;
733
- default:
734
- $info['audio']['lossless'] = false;
735
- break;
736
- }
737
- break;
738
- }
739
- break;
 
 
 
 
 
 
 
740
 
741
- default:
742
- switch ($atom_structure['sample_description_table'][$i]['data_format']) {
743
- case 'mp4s':
744
- $info['fileformat'] = 'mp4';
745
- break;
746
 
747
- default:
748
- // video atom
749
- $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
750
- $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
751
- $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
752
- $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
753
- $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4));
754
- $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
755
- $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
756
- $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2));
757
- $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1));
758
- $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']);
759
- $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
760
- $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
761
-
762
- $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
763
- $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
764
-
765
- if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
766
- $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
767
- $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
768
- $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
769
- $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
770
- $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
771
-
772
- $info['video']['codec'] = $info['quicktime']['video']['codec'];
773
- $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
774
- }
775
- $info['video']['lossless'] = false;
776
- $info['video']['pixel_aspect_ratio'] = (float) 1;
777
- break;
778
- }
779
- break;
780
- }
781
- switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
782
- case 'mp4a':
783
- $info['audio']['dataformat'] = 'mp4';
784
- $info['quicktime']['audio']['codec'] = 'mp4';
785
- break;
786
 
787
- case '3ivx':
788
- case '3iv1':
789
- case '3iv2':
790
- $info['video']['dataformat'] = '3ivx';
791
- break;
792
 
793
- case 'xvid':
794
- $info['video']['dataformat'] = 'xvid';
795
- break;
796
 
797
- case 'mp4v':
798
- $info['video']['dataformat'] = 'mpeg4';
799
- break;
800
 
801
- case 'divx':
802
- case 'div1':
803
- case 'div2':
804
- case 'div3':
805
- case 'div4':
806
- case 'div5':
807
- case 'div6':
808
- $info['video']['dataformat'] = 'divx';
809
- break;
810
 
811
- default:
812
- // do nothing
813
- break;
 
 
814
  }
815
- unset($atom_structure['sample_description_table'][$i]['data']);
816
- }
817
- break;
818
 
819
 
820
- case 'stts': // Sample Table Time-to-Sample atom
821
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
822
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
823
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
824
- $sttsEntriesDataOffset = 8;
825
- //$FrameRateCalculatorArray = array();
826
- $frames_count = 0;
827
 
828
- $max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
829
- if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
830
- $info['warning'][] = 'QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).';
831
- }
832
- for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
833
- $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
834
- $sttsEntriesDataOffset += 4;
835
- $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
836
- $sttsEntriesDataOffset += 4;
837
-
838
- $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
839
-
840
- // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
841
- //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
842
- // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
843
- // if ($stts_new_framerate <= 60) {
844
- // // some atoms have durations of "1" giving a very large framerate, which probably is not right
845
- // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
  // }
 
 
847
  //}
848
- //
849
- //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
850
- }
851
- $info['quicktime']['stts_framecount'][] = $frames_count;
852
- //$sttsFramesTotal = 0;
853
- //$sttsSecondsTotal = 0;
854
- //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
855
- // if (($frames_per_second > 60) || ($frames_per_second < 1)) {
856
- // // not video FPS information, probably audio information
857
- // $sttsFramesTotal = 0;
858
- // $sttsSecondsTotal = 0;
859
- // break;
860
- // }
861
- // $sttsFramesTotal += $frame_count;
862
- // $sttsSecondsTotal += $frame_count / $frames_per_second;
863
- //}
864
- //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
865
- // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
866
- // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
867
- // }
868
- //}
869
- break;
870
 
871
 
872
- case 'stss': // Sample Table Sync Sample (key frames) atom
873
- if ($ParseAllPossibleAtoms) {
874
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
875
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
876
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
877
- $stssEntriesDataOffset = 8;
878
- for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
879
- $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
880
- $stssEntriesDataOffset += 4;
 
881
  }
882
- }
883
- break;
884
 
885
 
886
- case 'stsc': // Sample Table Sample-to-Chunk atom
887
- if ($ParseAllPossibleAtoms) {
888
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
889
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
890
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
891
- $stscEntriesDataOffset = 8;
892
- for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
893
- $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
894
- $stscEntriesDataOffset += 4;
895
- $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
896
- $stscEntriesDataOffset += 4;
897
- $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
898
- $stscEntriesDataOffset += 4;
 
899
  }
900
- }
901
- break;
902
 
903
 
904
- case 'stsz': // Sample Table SiZe atom
905
- if ($ParseAllPossibleAtoms) {
906
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
907
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
908
- $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
909
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
910
- $stszEntriesDataOffset = 12;
911
- if ($atom_structure['sample_size'] == 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
912
  for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
913
- $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
914
- $stszEntriesDataOffset += 4;
915
  }
916
  }
917
- }
918
- break;
919
 
920
 
921
- case 'stco': // Sample Table Chunk Offset atom
922
- if ($ParseAllPossibleAtoms) {
923
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
924
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
925
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
926
- $stcoEntriesDataOffset = 8;
927
- for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
928
- $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
929
- $stcoEntriesDataOffset += 4;
 
930
  }
931
- }
932
- break;
933
 
934
 
935
- case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
936
- if ($ParseAllPossibleAtoms) {
937
  $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
938
  $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
939
  $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
940
- $stcoEntriesDataOffset = 8;
941
  for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
942
- $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
943
- $stcoEntriesDataOffset += 8;
 
 
 
 
 
 
 
 
 
 
944
  }
945
- }
946
- break;
947
 
948
 
949
- case 'dref': // Data REFerence atom
950
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
951
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
952
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
953
- $drefDataOffset = 8;
954
- for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
955
- $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
956
- $drefDataOffset += 4;
957
- $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
958
- $drefDataOffset += 4;
959
- $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
960
- $drefDataOffset += 1;
961
- $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000
962
- $drefDataOffset += 3;
963
- $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
964
- $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
965
-
966
- $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
967
- }
968
- break;
969
 
970
 
971
- case 'gmin': // base Media INformation atom
972
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
973
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
974
- $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
975
- $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
976
- $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
977
- $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
978
- $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
979
- $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
980
- break;
981
 
982
 
983
- case 'smhd': // Sound Media information HeaDer atom
984
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
985
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
986
- $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
987
- $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
988
- break;
 
989
 
 
 
990
 
991
- case 'vmhd': // Video Media information HeaDer atom
992
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
993
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
994
- $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
995
- $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
996
- $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
997
- $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
998
 
999
- $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
1000
- break;
 
 
 
 
 
 
 
1001
 
 
 
 
 
1002
 
1003
- case 'hdlr': // HanDLeR reference atom
1004
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1005
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1006
- $atom_structure['component_type'] = substr($atom_data, 4, 4);
1007
- $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
1008
- $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
1009
- $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1010
- $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1011
- $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
1012
 
1013
- if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
1014
- $info['video']['dataformat'] = 'quicktimevr';
1015
- }
1016
- break;
 
 
 
 
 
1017
 
 
 
 
 
 
1018
 
1019
- case 'mdhd': // MeDia HeaDer atom
1020
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1021
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1022
- $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1023
- $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1024
- $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1025
- $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1026
- $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
1027
- $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
1028
 
1029
- if ($atom_structure['time_scale'] == 0) {
1030
- $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
1031
- return false;
1032
- }
1033
- $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1034
-
1035
- $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1036
- $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1037
- $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
1038
- $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
1039
- if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
1040
- $info['comments']['language'][] = $atom_structure['language'];
1041
- }
1042
- break;
1043
 
 
 
 
 
 
1044
 
1045
- case 'pnot': // Preview atom
1046
- $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"
1047
- $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00
1048
- $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
1049
- $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
1050
 
1051
- $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
1052
- break;
1053
 
 
 
 
 
 
1054
 
1055
- case 'crgn': // Clipping ReGioN atom
1056
- $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box,
1057
- $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields
1058
- $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
1059
- break;
1060
 
 
 
 
 
 
1061
 
1062
- case 'load': // track LOAD settings atom
1063
- $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
1064
- $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1065
- $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1066
- $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1067
 
1068
- $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
1069
- $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
1070
- break;
1071
 
 
 
 
 
 
 
 
 
 
1072
 
1073
- case 'tmcd': // TiMe CoDe atom
1074
- case 'chap': // CHAPter list atom
1075
- case 'sync': // SYNChronization atom
1076
- case 'scpt': // tranSCriPT atom
1077
- case 'ssrc': // non-primary SouRCe atom
1078
- for ($i = 0; $i < strlen($atom_data); $i += 4) {
1079
- @$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1080
- }
1081
- break;
1082
 
 
 
 
 
 
 
 
 
 
 
1083
 
1084
- case 'elst': // Edit LiST atom
1085
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1086
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1087
- $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1088
- for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
1089
- $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
1090
- $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
1091
- $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
1092
- }
1093
- break;
1094
 
 
 
 
 
 
1095
 
1096
- case 'kmat': // compressed MATte atom
1097
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1098
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1099
- $atom_structure['matte_data_raw'] = substr($atom_data, 4);
1100
- break;
1101
 
 
 
 
 
 
 
 
 
 
 
 
1102
 
1103
- case 'ctab': // Color TABle atom
1104
- $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000
1105
- $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000
1106
- $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1;
1107
- for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
1108
- $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
1109
- $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
1110
- $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
1111
- $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
1112
- }
1113
- break;
1114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1115
 
1116
- case 'mvhd': // MoVie HeaDer atom
1117
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1118
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1119
- $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1120
- $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1121
- $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1122
- $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1123
- $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
1124
- $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
1125
- $atom_structure['reserved'] = substr($atom_data, 26, 10);
1126
- $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
1127
- $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1128
- $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
1129
- $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
1130
- $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1131
- $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
1132
- $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
1133
- $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1134
- $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
1135
- $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
1136
- $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
1137
- $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
1138
- $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
1139
- $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
1140
- $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
1141
- $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
1142
-
1143
- if ($atom_structure['time_scale'] == 0) {
1144
- $info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
1145
- return false;
1146
- }
1147
- $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1148
- $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1149
- $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1150
- $info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
1151
- $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
1152
- break;
1153
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1154
 
1155
- case 'tkhd': // TracK HeaDer atom
1156
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1157
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1158
- $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1159
- $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1160
- $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1161
- $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1162
- $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1163
- $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
1164
- $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
1165
- $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
1166
- $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
1167
- $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
1168
- // http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
1169
- // http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
1170
- $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1171
- $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
1172
- $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
1173
- $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1174
- $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
1175
- $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
1176
- $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1177
- $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
1178
- $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
1179
- $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
1180
- $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
1181
- $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001);
1182
- $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002);
1183
- $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
1184
- $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008);
1185
- $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1186
- $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1187
-
1188
- if ($atom_structure['flags']['enabled'] == 1) {
1189
- if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
1190
- $info['video']['resolution_x'] = $atom_structure['width'];
1191
- $info['video']['resolution_y'] = $atom_structure['height'];
1192
  }
1193
- $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
1194
- $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
1195
- $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
1196
- $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
1197
- } else {
1198
- // see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295
1199
- //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
1200
- //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
1201
- //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); }
1202
- }
1203
- break;
 
 
 
 
 
 
1204
 
1205
 
1206
- case 'iods': // Initial Object DeScriptor atom
1207
- // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
1208
- // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
1209
- $offset = 0;
1210
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1211
- $offset += 1;
1212
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
1213
- $offset += 3;
1214
- $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1215
- $offset += 1;
1216
- $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1217
- //$offset already adjusted by quicktime_read_mp4_descr_length()
1218
- $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
1219
- $offset += 2;
1220
- $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1221
- $offset += 1;
1222
- $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1223
- $offset += 1;
1224
- $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1225
- $offset += 1;
1226
- $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1227
- $offset += 1;
1228
- $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1229
- $offset += 1;
1230
-
1231
- $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
1232
- for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) {
1233
- $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1234
  $offset += 1;
1235
- $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1236
  //$offset already adjusted by quicktime_read_mp4_descr_length()
1237
- $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
1238
- $offset += 4;
1239
- }
 
 
 
 
 
 
 
 
 
1240
 
1241
- $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
1242
- $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
1243
- break;
 
 
 
 
 
 
1244
 
1245
- case 'ftyp': // FileTYPe (?) atom (for MP4 it seems)
1246
- $atom_structure['signature'] = substr($atom_data, 0, 4);
1247
- $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1248
- $atom_structure['fourcc'] = substr($atom_data, 8, 4);
1249
- break;
 
 
 
 
1250
 
1251
- case 'mdat': // Media DATa atom
1252
- // 'mdat' contains the actual data for the audio/video, possibly also subtitles
1253
 
1254
- /* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to info@getid3.org */
1255
 
1256
- // first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?)
1257
- $mdat_offset = 0;
1258
- while (true) {
1259
- if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') {
1260
- $mdat_offset += 8;
1261
- } elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') {
1262
- $mdat_offset += 8;
1263
- } else {
1264
- break;
 
 
 
 
 
 
 
 
 
 
 
 
1265
  }
1266
- }
1267
 
1268
- // check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
1269
- while (($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
1270
- && ($chapter_string_length < 1000)
1271
- && ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
1272
- && preg_match('#^[\x20-\xFF]+$#', substr($atom_data, $mdat_offset + 2, $chapter_string_length), $chapter_matches)) {
1273
- $mdat_offset += (2 + $chapter_string_length);
1274
- @$info['quicktime']['comments']['chapters'][] = $chapter_matches[0];
1275
- }
 
 
 
 
 
 
 
1276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1277
 
 
1278
 
1279
- if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
 
1280
 
1281
- $info['avdataoffset'] = $atom_structure['offset'] + 8; // $info['quicktime'][$atomname]['offset'] + 8;
1282
- $OldAVDataEnd = $info['avdataend'];
1283
- $info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
 
 
 
 
 
 
 
 
 
 
1284
 
1285
- $getid3_temp = new getID3();
1286
- $getid3_temp->openfile($this->getid3->filename);
1287
- $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1288
- $getid3_temp->info['avdataend'] = $info['avdataend'];
1289
- $getid3_mp3 = new getid3_mp3($getid3_temp);
1290
- if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) {
1291
- $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1292
- if (!empty($getid3_temp->info['warning'])) {
1293
- foreach ($getid3_temp->info['warning'] as $value) {
1294
- $info['warning'][] = $value;
1295
- }
1296
- }
1297
- if (!empty($getid3_temp->info['mpeg'])) {
1298
- $info['mpeg'] = $getid3_temp->info['mpeg'];
1299
- if (isset($info['mpeg']['audio'])) {
1300
- $info['audio']['dataformat'] = 'mp3';
1301
- $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
1302
- $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
1303
- $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
1304
- $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
1305
- $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1306
- $info['bitrate'] = $info['audio']['bitrate'];
1307
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1308
  }
 
 
1309
  }
1310
- unset($getid3_mp3, $getid3_temp);
1311
- $info['avdataend'] = $OldAVDataEnd;
1312
- unset($OldAVDataEnd);
1313
 
1314
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1315
 
1316
- unset($mdat_offset, $chapter_string_length, $chapter_matches);
1317
- break;
 
 
1318
 
1319
- case 'free': // FREE space atom
1320
- case 'skip': // SKIP atom
1321
- case 'wide': // 64-bit expansion placeholder atom
1322
- // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
1323
-
1324
- // When writing QuickTime files, it is sometimes necessary to update an atom's size.
1325
- // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
1326
- // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
1327
- // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
1328
- // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
1329
- // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
1330
- // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
1331
- break;
1332
 
 
 
1333
 
1334
- case 'nsav': // NoSAVe atom
1335
- // http://developer.apple.com/technotes/tn/tn2038.html
1336
- $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
1337
- break;
1338
 
1339
- case 'ctyp': // Controller TYPe atom (seen on QTVR)
1340
- // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
1341
- // some controller names are:
1342
- // 0x00 + 'std' for linear movie
1343
- // 'none' for no controls
1344
- $atom_structure['ctyp'] = substr($atom_data, 0, 4);
1345
- $info['quicktime']['controller'] = $atom_structure['ctyp'];
1346
- switch ($atom_structure['ctyp']) {
1347
- case 'qtvr':
1348
- $info['video']['dataformat'] = 'quicktimevr';
1349
- break;
1350
- }
1351
- break;
1352
 
1353
- case 'pano': // PANOrama track (seen on QTVR)
1354
- $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
1355
- break;
 
1356
 
1357
- case 'hint': // HINT track
1358
- case 'hinf': //
1359
- case 'hinv': //
1360
- case 'hnti': //
1361
- $info['quicktime']['hinting'] = true;
1362
- break;
 
 
 
 
 
 
 
 
 
 
 
1363
 
1364
- case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
1365
- for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
1366
- $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1367
- }
1368
- break;
 
 
 
 
 
 
 
 
1369
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1370
 
1371
- // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
1372
- case 'FXTC': // Something to do with Adobe After Effects (?)
1373
- case 'PrmA':
1374
- case 'code':
1375
- case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
1376
- case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
1377
- // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
1378
- // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
1379
- // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
1380
- case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1381
- case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1382
- case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1383
- case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1384
- //$atom_structure['data'] = $atom_data;
1385
- break;
1386
 
1387
- case "\xA9".'xyz': // GPS latitude+longitude+altitude
1388
- $atom_structure['data'] = $atom_data;
1389
- if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
1390
- @list($all, $latitude, $longitude, $altitude) = $matches;
1391
- $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude);
1392
- $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
1393
- if (!empty($altitude)) {
1394
- $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
 
 
 
1395
  }
1396
- } else {
1397
- $info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.';
1398
- }
1399
- break;
1400
 
1401
- case 'NCDT':
1402
- // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1403
- // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
1404
- $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1405
- break;
1406
- case 'NCTH': // Nikon Camera THumbnail image
1407
- case 'NCVW': // Nikon Camera preVieW image
1408
- // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1409
- if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
1410
- $atom_structure['data'] = $atom_data;
1411
- $atom_structure['image_mime'] = 'image/jpeg';
1412
- $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
1413
- $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
1414
- }
1415
- break;
1416
- case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1417
- $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
1418
- break;
1419
- case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1420
- case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1421
- case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
1422
- $atom_structure['data'] = $atom_data;
1423
- break;
1424
 
1425
- case "\x00\x00\x00\x00":
1426
- case 'meta': // METAdata atom
1427
- // some kind of metacontainer, may contain a big data dump such as:
1428
- // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
1429
- // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1430
 
1431
- $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1432
- $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1433
- $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1434
- //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1435
- break;
1436
 
1437
- case 'data': // metaDATA atom
1438
- // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
1439
- $atom_structure['language'] = substr($atom_data, 4 + 0, 2);
1440
- $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
1441
- $atom_structure['data'] = substr($atom_data, 4 + 4);
1442
- break;
1443
 
1444
- default:
1445
- $info['warning'][] = 'Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
1446
- $atom_structure['data'] = $atom_data;
1447
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1448
  }
1449
  array_pop($atomHierarchy);
1450
  return $atom_structure;
1451
  }
1452
 
 
 
 
 
 
 
 
 
1453
  public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
1454
- //echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
1455
  $atom_structure = false;
1456
  $subatomoffset = 0;
1457
  $subatomcounter = 0;
@@ -1466,18 +1874,24 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1466
  // Furthermore, for historical reasons the list of atoms is optionally
1467
  // terminated by a 32-bit integer set to 0. If you are writing a program
1468
  // to read user data atoms, you should allow for the terminating 0.
 
 
 
 
1469
  return $atom_structure;
1470
  }
1471
-
1472
- $atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
1473
-
1474
  $subatomoffset += $subatomsize;
1475
- $subatomcounter++;
1476
  }
1477
  return $atom_structure;
1478
  }
1479
 
1480
-
 
 
 
 
 
1481
  public function quicktime_read_mp4_descr_length($data, &$offset) {
1482
  // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
1483
  $num_bytes = 0;
@@ -1489,7 +1903,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1489
  return $length;
1490
  }
1491
 
1492
-
 
 
 
 
1493
  public function QuicktimeLanguageLookup($languageid) {
1494
  // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
1495
  static $QuicktimeLanguageLookup = array();
@@ -1627,6 +2045,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1627
  return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
1628
  }
1629
 
 
 
 
 
 
1630
  public function QuicktimeVideoCodecLookup($codecid) {
1631
  static $QuicktimeVideoCodecLookup = array();
1632
  if (empty($QuicktimeVideoCodecLookup)) {
@@ -1686,6 +2109,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1686
  return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
1687
  }
1688
 
 
 
 
 
 
1689
  public function QuicktimeAudioCodecLookup($codecid) {
1690
  static $QuicktimeAudioCodecLookup = array();
1691
  if (empty($QuicktimeAudioCodecLookup)) {
@@ -1731,6 +2159,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1731
  return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
1732
  }
1733
 
 
 
 
 
 
1734
  public function QuicktimeDCOMLookup($compressionid) {
1735
  static $QuicktimeDCOMLookup = array();
1736
  if (empty($QuicktimeDCOMLookup)) {
@@ -1740,6 +2173,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1740
  return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
1741
  }
1742
 
 
 
 
 
 
1743
  public function QuicktimeColorNameLookup($colordepthid) {
1744
  static $QuicktimeColorNameLookup = array();
1745
  if (empty($QuicktimeColorNameLookup)) {
@@ -1758,6 +2196,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1758
  return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
1759
  }
1760
 
 
 
 
 
 
1761
  public function QuicktimeSTIKLookup($stik) {
1762
  static $QuicktimeSTIKLookup = array();
1763
  if (empty($QuicktimeSTIKLookup)) {
@@ -1775,66 +2218,75 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1775
  return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
1776
  }
1777
 
 
 
 
 
 
1778
  public function QuicktimeIODSaudioProfileName($audio_profile_id) {
1779
  static $QuicktimeIODSaudioProfileNameLookup = array();
1780
  if (empty($QuicktimeIODSaudioProfileNameLookup)) {
1781
  $QuicktimeIODSaudioProfileNameLookup = array(
1782
- 0x00 => 'ISO Reserved (0x00)',
1783
- 0x01 => 'Main Audio Profile @ Level 1',
1784
- 0x02 => 'Main Audio Profile @ Level 2',
1785
- 0x03 => 'Main Audio Profile @ Level 3',
1786
- 0x04 => 'Main Audio Profile @ Level 4',
1787
- 0x05 => 'Scalable Audio Profile @ Level 1',
1788
- 0x06 => 'Scalable Audio Profile @ Level 2',
1789
- 0x07 => 'Scalable Audio Profile @ Level 3',
1790
- 0x08 => 'Scalable Audio Profile @ Level 4',
1791
- 0x09 => 'Speech Audio Profile @ Level 1',
1792
- 0x0A => 'Speech Audio Profile @ Level 2',
1793
- 0x0B => 'Synthetic Audio Profile @ Level 1',
1794
- 0x0C => 'Synthetic Audio Profile @ Level 2',
1795
- 0x0D => 'Synthetic Audio Profile @ Level 3',
1796
- 0x0E => 'High Quality Audio Profile @ Level 1',
1797
- 0x0F => 'High Quality Audio Profile @ Level 2',
1798
- 0x10 => 'High Quality Audio Profile @ Level 3',
1799
- 0x11 => 'High Quality Audio Profile @ Level 4',
1800
- 0x12 => 'High Quality Audio Profile @ Level 5',
1801
- 0x13 => 'High Quality Audio Profile @ Level 6',
1802
- 0x14 => 'High Quality Audio Profile @ Level 7',
1803
- 0x15 => 'High Quality Audio Profile @ Level 8',
1804
- 0x16 => 'Low Delay Audio Profile @ Level 1',
1805
- 0x17 => 'Low Delay Audio Profile @ Level 2',
1806
- 0x18 => 'Low Delay Audio Profile @ Level 3',
1807
- 0x19 => 'Low Delay Audio Profile @ Level 4',
1808
- 0x1A => 'Low Delay Audio Profile @ Level 5',
1809
- 0x1B => 'Low Delay Audio Profile @ Level 6',
1810
- 0x1C => 'Low Delay Audio Profile @ Level 7',
1811
- 0x1D => 'Low Delay Audio Profile @ Level 8',
1812
- 0x1E => 'Natural Audio Profile @ Level 1',
1813
- 0x1F => 'Natural Audio Profile @ Level 2',
1814
- 0x20 => 'Natural Audio Profile @ Level 3',
1815
- 0x21 => 'Natural Audio Profile @ Level 4',
1816
- 0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
1817
- 0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
1818
- 0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
1819
- 0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
1820
- 0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
1821
- 0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
1822
- 0x28 => 'AAC Profile @ Level 1',
1823
- 0x29 => 'AAC Profile @ Level 2',
1824
- 0x2A => 'AAC Profile @ Level 4',
1825
- 0x2B => 'AAC Profile @ Level 5',
1826
- 0x2C => 'High Efficiency AAC Profile @ Level 2',
1827
- 0x2D => 'High Efficiency AAC Profile @ Level 3',
1828
- 0x2E => 'High Efficiency AAC Profile @ Level 4',
1829
- 0x2F => 'High Efficiency AAC Profile @ Level 5',
1830
- 0xFE => 'Not part of MPEG-4 audio profiles',
1831
- 0xFF => 'No audio capability required',
1832
  );
1833
  }
1834
  return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
1835
  }
1836
 
1837
-
 
 
 
 
1838
  public function QuicktimeIODSvideoProfileName($video_profile_id) {
1839
  static $QuicktimeIODSvideoProfileNameLookup = array();
1840
  if (empty($QuicktimeIODSvideoProfileNameLookup)) {
@@ -1906,7 +2358,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1906
  return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
1907
  }
1908
 
1909
-
 
 
 
 
1910
  public function QuicktimeContentRatingLookup($rtng) {
1911
  static $QuicktimeContentRatingLookup = array();
1912
  if (empty($QuicktimeContentRatingLookup)) {
@@ -1917,6 +2373,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1917
  return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
1918
  }
1919
 
 
 
 
 
 
1920
  public function QuicktimeStoreAccountTypeLookup($akid) {
1921
  static $QuicktimeStoreAccountTypeLookup = array();
1922
  if (empty($QuicktimeStoreAccountTypeLookup)) {
@@ -1926,6 +2387,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1926
  return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
1927
  }
1928
 
 
 
 
 
 
1929
  public function QuicktimeStoreFrontCodeLookup($sfid) {
1930
  static $QuicktimeStoreFrontCodeLookup = array();
1931
  if (empty($QuicktimeStoreFrontCodeLookup)) {
@@ -1955,6 +2421,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1955
  return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
1956
  }
1957
 
 
 
 
 
 
1958
  public function QuicktimeParseNikonNCTG($atom_data) {
1959
  // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1960
  // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
@@ -1997,10 +2468,10 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
1997
  );
1998
 
1999
  $offset = 0;
 
2000
  $datalength = strlen($atom_data);
2001
  $parsed = array();
2002
  while ($offset < $datalength) {
2003
- //echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
2004
  $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;
2005
  $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
2006
  $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
@@ -2055,7 +2526,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
2055
  $offset += ($data_size * 2);
2056
  break;
2057
  default:
2058
- echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
2059
  break 2;
2060
  }
2061
 
@@ -2133,7 +2604,13 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
2133
  return $parsed;
2134
  }
2135
 
2136
-
 
 
 
 
 
 
2137
  public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
2138
  static $handyatomtranslatorarray = array();
2139
  if (empty($handyatomtranslatorarray)) {
@@ -2230,8 +2707,8 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
2230
  $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id';
2231
 
2232
  // http://age.hobba.nl/audio/tag_frame_reference.html
2233
- $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
2234
- $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
2235
  */
2236
  }
2237
  $info = &$this->getid3->info;
@@ -2257,11 +2734,59 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
2257
  $data = array('data'=>$data, 'image_mime'=>$image_mime);
2258
  }
2259
  }
2260
- $info['quicktime']['comments'][$comment_key][] = $data;
 
 
 
 
 
 
 
2261
  }
2262
  return true;
2263
  }
2264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2265
  public function NoNullString($nullterminatedstring) {
2266
  // remove the single null terminator on null terminated strings
2267
  if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
@@ -2270,9 +2795,111 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
2270
  return $nullterminatedstring;
2271
  }
2272
 
 
 
 
 
 
2273
  public function Pascal2String($pascalstring) {
2274
  // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
2275
  return substr($pascalstring, 1);
2276
  }
2277
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2278
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.quicktime.php //
24
  public $ReturnAtomData = true;
25
  public $ParseAllPossibleAtoms = false;
26
 
27
+ /**
28
+ * @return bool
29
+ */
30
  public function Analyze() {
31
  $info = &$this->getid3->info;
32
 
38
 
39
  $offset = 0;
40
  $atomcounter = 0;
41
+ $atom_data_read_buffer_size = max($this->getid3->option_fread_buffer_size * 1024, ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : 1024)); // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
42
  while ($offset < $info['avdataend']) {
43
  if (!getid3_lib::intValueSupported($offset)) {
44
+ $this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
45
  break;
46
  }
47
  $this->fseek($offset);
60
  $info['quicktime'][$atomname]['offset'] = $offset;
61
 
62
  if (($offset + $atomsize) > $info['avdataend']) {
63
+ $this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)');
64
  return false;
65
  }
66
 
84
  unset($info['avdataend_tmp']);
85
  }
86
 
87
+ if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
88
+ $durations = $this->quicktime_time_to_sample_table($info);
89
+ for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
90
+ $bookmark = array();
91
+ $bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
92
+ if (isset($durations[$i])) {
93
+ $bookmark['duration_sample'] = $durations[$i]['sample_duration'];
94
+ if ($i > 0) {
95
+ $bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample'];
96
+ } else {
97
+ $bookmark['start_sample'] = 0;
98
+ }
99
+ if ($time_scale = $this->quicktime_bookmark_time_scale($info)) {
100
+ $bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale;
101
+ $bookmark['start_seconds'] = $bookmark['start_sample'] / $time_scale;
102
+ }
103
+ }
104
+ $info['quicktime']['bookmarks'][] = $bookmark;
105
+ }
106
+ }
107
+
108
+ if (isset($info['quicktime']['temp_meta_key_names'])) {
109
+ unset($info['quicktime']['temp_meta_key_names']);
110
+ }
111
+
112
+ if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
113
+ // https://en.wikipedia.org/wiki/ISO_6709
114
+ foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
115
+ $latitude = false;
116
+ $longitude = false;
117
+ $altitude = false;
118
+ if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) {
119
+ @list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches;
120
+
121
+ if (strlen($lat_deg) == 2) { // [+-]DD.D
122
+ $latitude = floatval(ltrim($lat_deg, '0').$lat_deg_dec);
123
+ } elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M
124
+ $latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60);
125
+ } elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S
126
+ $latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600);
127
+ }
128
+
129
+ if (strlen($lon_deg) == 3) { // [+-]DDD.D
130
+ $longitude = floatval(ltrim($lon_deg, '0').$lon_deg_dec);
131
+ } elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M
132
+ $longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60);
133
+ } elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S
134
+ $longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600);
135
+ }
136
+
137
+ if (strlen($alt_deg) == 3) { // [+-]DDD.D
138
+ $altitude = floatval(ltrim($alt_deg, '0').$alt_deg_dec);
139
+ } elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M
140
+ $altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60);
141
+ } elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S
142
+ $altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600);
143
+ }
144
+
145
+ if ($latitude !== false) {
146
+ $info['quicktime']['comments']['gps_latitude'][] = (($lat_sign == '-') ? -1 : 1) * floatval($latitude);
147
+ }
148
+ if ($longitude !== false) {
149
+ $info['quicktime']['comments']['gps_longitude'][] = (($lon_sign == '-') ? -1 : 1) * floatval($longitude);
150
+ }
151
+ if ($altitude !== false) {
152
+ $info['quicktime']['comments']['gps_altitude'][] = (($alt_sign == '-') ? -1 : 1) * floatval($altitude);
153
+ }
154
+ }
155
+ if ($latitude === false) {
156
+ $this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug');
157
+ }
158
+ break;
159
+ }
160
+ }
161
+
162
  if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
163
  $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
164
  }
165
  if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
166
  $info['audio']['bitrate'] = $info['bitrate'];
167
  }
168
+ if (!empty($info['bitrate']) && !empty($info['audio']['bitrate']) && empty($info['video']['bitrate']) && !empty($info['video']['frame_rate']) && !empty($info['video']['resolution_x']) && ($info['bitrate'] > $info['audio']['bitrate'])) {
169
+ $info['video']['bitrate'] = $info['bitrate'] - $info['audio']['bitrate'];
170
+ }
171
  if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
172
  foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
173
  $samples_per_second = $samples_count / $info['playtime_seconds'];
179
  }
180
  }
181
  }
182
+ if ($info['audio']['dataformat'] == 'mp4') {
183
  $info['fileformat'] = 'mp4';
184
+ if (empty($info['video']['resolution_x'])) {
185
+ $info['mime_type'] = 'audio/mp4';
186
+ unset($info['video']['dataformat']);
187
+ } else {
188
+ $info['mime_type'] = 'video/mp4';
189
+ }
190
  }
191
 
192
  if (!$this->ReturnAtomData) {
199
  if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
200
  $info['video']['dataformat'] = 'quicktime';
201
  }
202
+ if (isset($info['video']) && ($info['mime_type'] == 'audio/mp4') && empty($info['video']['resolution_x']) && empty($info['video']['resolution_y'])) {
203
+ unset($info['video']);
204
+ }
205
 
206
  return true;
207
  }
208
 
209
+ /**
210
+ * @param string $atomname
211
+ * @param int $atomsize
212
+ * @param string $atom_data
213
+ * @param int $baseoffset
214
+ * @param array $atomHierarchy
215
+ * @param bool $ParseAllPossibleAtoms
216
+ *
217
+ * @return array|false
218
+ */
219
  public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
220
  // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
221
  // https://code.google.com/p/mp4v2/wiki/iTunesMetadata
222
 
223
  $info = &$this->getid3->info;
224
 
225
+ $atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717
226
  array_push($atomHierarchy, $atomname);
227
  $atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
228
  $atom_structure['name'] = $atomname;
229
  $atom_structure['size'] = $atomsize;
230
  $atom_structure['offset'] = $baseoffset;
231
+ if (substr($atomname, 0, 3) == "\x00\x00\x00") {
232
+ // https://github.com/JamesHeinrich/getID3/issues/139
233
+ $atomname = getid3_lib::BigEndian2Int($atomname);
234
+ $atom_structure['name'] = $atomname;
235
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
236
+ } else {
237
+ switch ($atomname) {
238
+ case 'moov': // MOVie container atom
239
+ case 'trak': // TRAcK container atom
240
+ case 'clip': // CLIPping container atom
241
+ case 'matt': // track MATTe container atom
242
+ case 'edts': // EDiTS container atom
243
+ case 'tref': // Track REFerence container atom
244
+ case 'mdia': // MeDIA container atom
245
+ case 'minf': // Media INFormation container atom
246
+ case 'dinf': // Data INFormation container atom
247
+ case 'udta': // User DaTA container atom
248
+ case 'cmov': // Compressed MOVie container atom
249
+ case 'rmra': // Reference Movie Record Atom
250
+ case 'rmda': // Reference Movie Descriptor Atom
251
+ case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
252
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
253
+ break;
254
 
255
+ case 'ilst': // Item LiST container atom
256
+ if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
257
+ // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
258
+ $allnumericnames = true;
 
 
 
 
 
 
 
 
259
  foreach ($atom_structure['subatoms'] as $subatomarray) {
260
+ if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
261
+ $allnumericnames = false;
 
262
  break;
263
  }
264
  }
265
+ if ($allnumericnames) {
266
+ $newData = array();
267
+ foreach ($atom_structure['subatoms'] as $subatomarray) {
268
+ foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
269
+ unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
270
+ $newData[$subatomarray['name']] = $newData_subatomarray;
271
+ break;
272
+ }
273
+ }
274
+ $atom_structure['data'] = $newData;
275
+ unset($atom_structure['subatoms']);
276
+ }
277
  }
278
+ break;
 
 
 
 
 
 
 
 
 
 
 
279
 
280
+ case 'stbl': // Sample TaBLe container atom
281
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
282
+ $isVideo = false;
283
+ $framerate = 0;
284
+ $framecount = 0;
285
+ foreach ($atom_structure['subatoms'] as $key => $value_array) {
286
+ if (isset($value_array['sample_description_table'])) {
287
+ foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
288
+ if (isset($value_array2['data_format'])) {
289
+ switch ($value_array2['data_format']) {
290
+ case 'avc1':
291
+ case 'mp4v':
292
+ // video data
293
+ $isVideo = true;
294
+ break;
295
+ case 'mp4a':
296
+ // audio data
297
+ break;
298
+ }
299
  }
300
  }
301
+ } elseif (isset($value_array['time_to_sample_table'])) {
302
+ foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
303
+ if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
304
+ $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
305
+ $framecount = $value_array2['sample_count'];
306
+ }
307
  }
308
  }
309
  }
310
+ if ($isVideo && $framerate) {
311
+ $info['quicktime']['video']['frame_rate'] = $framerate;
312
+ $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
313
+ }
314
+ if ($isVideo && $framecount) {
315
+ $info['quicktime']['video']['frame_count'] = $framecount;
316
+ }
317
+ break;
 
 
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
 
320
+ case "\xA9".'alb': // ALBum
321
+ case "\xA9".'ART': //
322
+ case "\xA9".'art': // ARTist
323
+ case "\xA9".'aut': //
324
+ case "\xA9".'cmt': // CoMmenT
325
+ case "\xA9".'com': // COMposer
326
+ case "\xA9".'cpy': //
327
+ case "\xA9".'day': // content created year
328
+ case "\xA9".'dir': //
329
+ case "\xA9".'ed1': //
330
+ case "\xA9".'ed2': //
331
+ case "\xA9".'ed3': //
332
+ case "\xA9".'ed4': //
333
+ case "\xA9".'ed5': //
334
+ case "\xA9".'ed6': //
335
+ case "\xA9".'ed7': //
336
+ case "\xA9".'ed8': //
337
+ case "\xA9".'ed9': //
338
+ case "\xA9".'enc': //
339
+ case "\xA9".'fmt': //
340
+ case "\xA9".'gen': // GENre
341
+ case "\xA9".'grp': // GRouPing
342
+ case "\xA9".'hst': //
343
+ case "\xA9".'inf': //
344
+ case "\xA9".'lyr': // LYRics
345
+ case "\xA9".'mak': //
346
+ case "\xA9".'mod': //
347
+ case "\xA9".'nam': // full NAMe
348
+ case "\xA9".'ope': //
349
+ case "\xA9".'PRD': //
350
+ case "\xA9".'prf': //
351
+ case "\xA9".'req': //
352
+ case "\xA9".'src': //
353
+ case "\xA9".'swr': //
354
+ case "\xA9".'too': // encoder
355
+ case "\xA9".'trk': // TRacK
356
+ case "\xA9".'url': //
357
+ case "\xA9".'wrn': //
358
+ case "\xA9".'wrt': // WRiTer
359
+ case '----': // itunes specific
360
+ case 'aART': // Album ARTist
361
+ case 'akID': // iTunes store account type
362
+ case 'apID': // Purchase Account
363
+ case 'atID': //
364
+ case 'catg': // CaTeGory
365
+ case 'cmID': //
366
+ case 'cnID': //
367
+ case 'covr': // COVeR artwork
368
+ case 'cpil': // ComPILation
369
+ case 'cprt': // CoPyRighT
370
+ case 'desc': // DESCription
371
+ case 'disk': // DISK number
372
+ case 'egid': // Episode Global ID
373
+ case 'geID': //
374
+ case 'gnre': // GeNRE
375
+ case 'hdvd': // HD ViDeo
376
+ case 'keyw': // KEYWord
377
+ case 'ldes': // Long DEScription
378
+ case 'pcst': // PodCaST
379
+ case 'pgap': // GAPless Playback
380
+ case 'plID': //
381
+ case 'purd': // PURchase Date
382
+ case 'purl': // Podcast URL
383
+ case 'rati': //
384
+ case 'rndu': //
385
+ case 'rpdu': //
386
+ case 'rtng': // RaTiNG
387
+ case 'sfID': // iTunes store country
388
+ case 'soaa': // SOrt Album Artist
389
+ case 'soal': // SOrt ALbum
390
+ case 'soar': // SOrt ARtist
391
+ case 'soco': // SOrt COmposer
392
+ case 'sonm': // SOrt NaMe
393
+ case 'sosn': // SOrt Show Name
394
+ case 'stik': //
395
+ case 'tmpo': // TeMPO (BPM)
396
+ case 'trkn': // TRacK Number
397
+ case 'tven': // tvEpisodeID
398
+ case 'tves': // TV EpiSode
399
+ case 'tvnn': // TV Network Name
400
+ case 'tvsh': // TV SHow Name
401
+ case 'tvsn': // TV SeasoN
402
+ if ($atom_parent == 'udta') {
403
+ // User data atom handler
404
+ $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
405
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
406
+ $atom_structure['data'] = substr($atom_data, 4);
407
+
408
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
409
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
410
+ $info['comments']['language'][] = $atom_structure['language'];
411
  }
412
  } else {
413
+ // Apple item list box atom handler
414
+ $atomoffset = 0;
415
+ if (substr($atom_data, 2, 2) == "\x10\xB5") {
416
+ // not sure what it means, but observed on iPhone4 data.
417
+ // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
418
+ while ($atomoffset < strlen($atom_data)) {
419
+ $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2));
420
+ $boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
421
+ $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
422
+ if ($boxsmallsize <= 1) {
423
+ $this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
424
+ $atom_structure['data'] = null;
425
+ $atomoffset = strlen($atom_data);
426
+ break;
427
+ }
428
+ switch ($boxsmalltype) {
429
+ case "\x10\xB5":
430
+ $atom_structure['data'] = $boxsmalldata;
431
+ break;
432
+ default:
433
+ $this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset);
434
+ $atom_structure['data'] = $atom_data;
435
+ break;
436
+ }
437
+ $atomoffset += (4 + $boxsmallsize);
438
  }
439
+ } else {
440
+ while ($atomoffset < strlen($atom_data)) {
441
+ $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
442
+ $boxtype = substr($atom_data, $atomoffset + 4, 4);
443
+ $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
444
+ if ($boxsize <= 1) {
445
+ $this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
446
+ $atom_structure['data'] = null;
447
+ $atomoffset = strlen($atom_data);
448
  break;
449
+ }
450
+ $atomoffset += $boxsize;
451
 
452
+ switch ($boxtype) {
453
+ case 'mean':
454
+ case 'name':
455
+ $atom_structure[$boxtype] = substr($boxdata, 4);
456
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
 
458
+ case 'data':
459
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1));
460
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3));
461
+ switch ($atom_structure['flags_raw']) {
462
+ case 0: // data flag
463
+ case 21: // tmpo/cpil flag
464
+ switch ($atomname) {
465
+ case 'cpil':
466
+ case 'hdvd':
467
+ case 'pcst':
468
+ case 'pgap':
469
+ // 8-bit integer (boolean)
470
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
471
+ break;
472
+
473
+ case 'tmpo':
474
+ // 16-bit integer
475
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
476
+ break;
477
+
478
+ case 'disk':
479
+ case 'trkn':
480
+ // binary
481
+ $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
482
+ $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
483
+ $atom_structure['data'] = empty($num) ? '' : $num;
484
+ $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
485
+ break;
486
+
487
+ case 'gnre':
488
+ // enum
489
+ $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
490
+ $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
491
+ break;
492
+
493
+ case 'rtng':
494
+ // 8-bit integer
495
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
496
+ $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
497
+ break;
498
+
499
+ case 'stik':
500
+ // 8-bit integer (enum)
501
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
502
+ $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
503
+ break;
504
+
505
+ case 'sfID':
506
+ // 32-bit integer
507
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
508
+ $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
509
+ break;
510
+
511
+ case 'egid':
512
+ case 'purl':
513
+ $atom_structure['data'] = substr($boxdata, 8);
514
+ break;
515
+
516
+ case 'plID':
517
+ // 64-bit integer
518
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));
519
+ break;
520
+
521
+ case 'covr':
522
+ $atom_structure['data'] = substr($boxdata, 8);
523
+ // not a foolproof check, but better than nothing
524
+ if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
525
+ $atom_structure['image_mime'] = 'image/jpeg';
526
+ } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
527
+ $atom_structure['image_mime'] = 'image/png';
528
+ } elseif (preg_match('#^GIF#', $atom_structure['data'])) {
529
+ $atom_structure['image_mime'] = 'image/gif';
530
+ }
531
+ break;
532
+
533
+ case 'atID':
534
+ case 'cnID':
535
+ case 'geID':
536
+ case 'tves':
537
+ case 'tvsn':
538
+ default:
539
+ // 32-bit integer
540
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
541
  }
542
+ break;
543
+
544
+ case 1: // text flag
545
+ case 13: // image flag
546
+ default:
547
+ $atom_structure['data'] = substr($boxdata, 8);
548
+ if ($atomname == 'covr') {
549
+ // not a foolproof check, but better than nothing
550
+ if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
551
+ $atom_structure['image_mime'] = 'image/jpeg';
552
+ } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
553
+ $atom_structure['image_mime'] = 'image/png';
554
+ } elseif (preg_match('#^GIF#', $atom_structure['data'])) {
555
+ $atom_structure['image_mime'] = 'image/gif';
556
+ }
557
+ }
558
+ break;
559
 
560
+ }
561
+ break;
562
 
563
+ default:
564
+ $this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset);
565
+ $atom_structure['data'] = $atom_data;
566
 
567
+ }
568
  }
569
  }
570
  }
571
+ $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
572
+ break;
 
573
 
574
 
575
+ case 'play': // auto-PLAY atom
576
+ $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
577
 
578
+ $info['quicktime']['autoplay'] = $atom_structure['autoplay'];
579
+ break;
580
 
581
 
582
+ case 'WLOC': // Window LOCation atom
583
+ $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
584
+ $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
585
+ break;
586
 
587
 
588
+ case 'LOOP': // LOOPing atom
589
+ case 'SelO': // play SELection Only atom
590
+ case 'AllF': // play ALL Frames atom
591
+ $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
592
+ break;
593
 
594
 
595
+ case 'name': //
596
+ case 'MCPS': // Media Cleaner PRo
597
+ case '@PRM': // adobe PReMiere version
598
+ case '@PRQ': // adobe PRemiere Quicktime version
599
+ $atom_structure['data'] = $atom_data;
600
+ break;
601
 
602
 
603
+ case 'cmvd': // Compressed MooV Data atom
604
+ // Code by ubergeekØubergeek*tv based on information from
605
+ // http://developer.apple.com/quicktime/icefloe/dispatch012.html
606
+ $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
607
 
608
+ $CompressedFileData = substr($atom_data, 4);
609
+ if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
610
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
611
+ } else {
612
+ $this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']);
613
+ }
614
+ break;
615
 
616
 
617
+ case 'dcom': // Data COMpression atom
618
+ $atom_structure['compression_id'] = $atom_data;
619
+ $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
620
+ break;
621
 
622
 
623
+ case 'rdrf': // Reference movie Data ReFerence atom
624
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
625
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
626
+ $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
627
 
628
+ $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);
629
+ $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
630
+ switch ($atom_structure['reference_type_name']) {
631
+ case 'url ':
632
+ $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));
633
+ break;
634
 
635
+ case 'alis':
636
+ $atom_structure['file_alias'] = substr($atom_data, 12);
637
+ break;
638
 
639
+ case 'rsrc':
640
+ $atom_structure['resource_alias'] = substr($atom_data, 12);
641
+ break;
642
 
643
+ default:
644
+ $atom_structure['data'] = substr($atom_data, 12);
645
+ break;
646
+ }
647
+ break;
648
 
649
 
650
+ case 'rmqu': // Reference Movie QUality atom
651
+ $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
652
+ break;
653
 
654
 
655
+ case 'rmcs': // Reference Movie Cpu Speed atom
656
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
657
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
658
+ $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
659
+ break;
660
 
661
 
662
+ case 'rmvc': // Reference Movie Version Check atom
663
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
664
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
665
+ $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);
666
+ $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
667
+ $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
668
+ $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
669
+ break;
670
 
671
 
672
+ case 'rmcd': // Reference Movie Component check atom
673
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
674
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
675
+ $atom_structure['component_type'] = substr($atom_data, 4, 4);
676
+ $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
677
+ $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
678
+ $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
679
+ $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
680
+ $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
681
+ break;
682
 
683
 
684
+ case 'rmdr': // Reference Movie Data Rate atom
685
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
686
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
687
+ $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
688
 
689
+ $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
690
+ break;
691
 
692
 
693
+ case 'rmla': // Reference Movie Language Atom
694
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
695
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
696
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
697
 
698
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
699
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
700
+ $info['comments']['language'][] = $atom_structure['language'];
701
+ }
702
+ break;
703
 
704
 
705
+ case 'ptv ': // Print To Video - defines a movie's full screen mode
706
+ // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
707
+ $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
708
+ $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
709
+ $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
710
+ $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
711
+ $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
712
+
713
+ $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
714
+ $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
715
+
716
+ $ptv_lookup[0] = 'normal';
717
+ $ptv_lookup[1] = 'double';
718
+ $ptv_lookup[2] = 'half';
719
+ $ptv_lookup[3] = 'full';
720
+ $ptv_lookup[4] = 'current';
721
+ if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
722
+ $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
723
+ } else {
724
+ $this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')');
725
+ }
726
+ break;
727
 
728
 
729
+ case 'stsd': // Sample Table Sample Description atom
730
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
731
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
732
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
 
734
+ // see: https://github.com/JamesHeinrich/getID3/issues/111
735
+ // Some corrupt files have been known to have high bits set in the number_entries field
736
+ // This field shouldn't really need to be 32-bits, values stores are likely in the range 1-100000
737
+ // Workaround: mask off the upper byte and throw a warning if it's nonzero
738
+ if ($atom_structure['number_entries'] > 0x000FFFFF) {
739
+ if ($atom_structure['number_entries'] > 0x00FFFFFF) {
740
+ $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Ignoring upper byte and interpreting this as 0x'.getid3_lib::PrintHexBytes(substr($atom_data, 5, 3), true, false).' = '.($atom_structure['number_entries'] & 0x00FFFFFF));
741
+ $atom_structure['number_entries'] = ($atom_structure['number_entries'] & 0x00FFFFFF);
742
+ } else {
743
+ $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Please report this to info@getid3.org referencing bug report #111');
744
+ }
745
+ }
746
 
747
+ $stsdEntriesDataOffset = 8;
748
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
749
+ $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
750
+ $stsdEntriesDataOffset += 4;
751
+ $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4);
752
+ $stsdEntriesDataOffset += 4;
753
+ $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
754
+ $stsdEntriesDataOffset += 6;
755
+ $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
756
+ $stsdEntriesDataOffset += 2;
757
+ $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
758
+ $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
759
+
760
+ $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
761
+ $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
762
+ $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
763
+
764
+ switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
765
+
766
+ case "\x00\x00\x00\x00":
767
+ // audio tracks
768
+ $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
769
+ $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2));
770
+ $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2));
771
+ $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2));
772
+ $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4));
773
+
774
+ // video tracks
775
+ // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
776
+ $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
777
+ $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
778
+ $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
779
+ $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
780
+ $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
781
+ $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
782
+ $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4));
783
+ $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2));
784
+ $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4);
785
+ $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2));
786
+ $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2));
787
+
788
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
789
+ case '2vuY':
790
+ case 'avc1':
791
+ case 'cvid':
792
+ case 'dvc ':
793
+ case 'dvcp':
794
+ case 'gif ':
795
+ case 'h263':
796
+ case 'jpeg':
797
+ case 'kpcd':
798
+ case 'mjpa':
799
+ case 'mjpb':
800
+ case 'mp4v':
801
+ case 'png ':
802
+ case 'raw ':
803
+ case 'rle ':
804
+ case 'rpza':
805
+ case 'smc ':
806
+ case 'SVQ1':
807
+ case 'SVQ3':
808
+ case 'tiff':
809
+ case 'v210':
810
+ case 'v216':
811
+ case 'v308':
812
+ case 'v408':
813
+ case 'v410':
814
+ case 'yuv2':
815
+ $info['fileformat'] = 'mp4';
816
+ $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
817
+ if ($this->QuicktimeVideoCodecLookup($info['video']['fourcc'])) {
818
+ $info['video']['fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']);
819
+ }
820
+
821
+ // https://www.getid3.org/phpBB3/viewtopic.php?t=1550
822
+ //if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
823
+ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
824
+ // assume that values stored here are more important than values stored in [tkhd] atom
825
+ $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
826
+ $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
827
+ $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
828
+ $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
829
+ }
830
+ break;
831
 
832
+ case 'qtvr':
833
+ $info['video']['dataformat'] = 'quicktimevr';
834
+ break;
835
 
836
+ case 'mp4a':
837
+ default:
838
+ $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
839
+ $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
840
+ $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels'];
841
+ $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
842
+ $info['audio']['codec'] = $info['quicktime']['audio']['codec'];
843
+ $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate'];
844
+ $info['audio']['channels'] = $info['quicktime']['audio']['channels'];
845
+ $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth'];
846
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
847
+ case 'raw ': // PCM
848
+ case 'alac': // Apple Lossless Audio Codec
849
+ case 'sowt': // signed/two's complement (Little Endian)
850
+ case 'twos': // signed/two's complement (Big Endian)
851
+ case 'in24': // 24-bit Integer
852
+ case 'in32': // 32-bit Integer
853
+ case 'fl32': // 32-bit Floating Point
854
+ case 'fl64': // 64-bit Floating Point
855
+ $info['audio']['lossless'] = $info['quicktime']['audio']['lossless'] = true;
856
+ $info['audio']['bitrate'] = $info['quicktime']['audio']['bitrate'] = $info['audio']['channels'] * $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'];
857
+ break;
858
+ default:
859
+ $info['audio']['lossless'] = false;
860
+ break;
861
+ }
862
+ break;
863
+ }
864
+ break;
865
 
866
+ default:
867
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
868
+ case 'mp4s':
869
+ $info['fileformat'] = 'mp4';
870
+ break;
871
 
872
+ default:
873
+ // video atom
874
+ $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
875
+ $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
876
+ $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
877
+ $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
878
+ $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4));
879
+ $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
880
+ $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
881
+ $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2));
882
+ $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1));
883
+ $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']);
884
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
885
+ $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
886
+
887
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
888
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
889
+
890
+ if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
891
+ $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
892
+ $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
893
+ $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
894
+ $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
895
+ $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
896
+
897
+ $info['video']['codec'] = $info['quicktime']['video']['codec'];
898
+ $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
899
+ }
900
+ $info['video']['lossless'] = false;
901
+ $info['video']['pixel_aspect_ratio'] = (float) 1;
902
+ break;
903
+ }
904
+ break;
905
+ }
906
+ switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
907
+ case 'mp4a':
908
+ $info['audio']['dataformat'] = 'mp4';
909
+ $info['quicktime']['audio']['codec'] = 'mp4';
910
+ break;
911
 
912
+ case '3ivx':
913
+ case '3iv1':
914
+ case '3iv2':
915
+ $info['video']['dataformat'] = '3ivx';
916
+ break;
917
 
918
+ case 'xvid':
919
+ $info['video']['dataformat'] = 'xvid';
920
+ break;
921
 
922
+ case 'mp4v':
923
+ $info['video']['dataformat'] = 'mpeg4';
924
+ break;
925
 
926
+ case 'divx':
927
+ case 'div1':
928
+ case 'div2':
929
+ case 'div3':
930
+ case 'div4':
931
+ case 'div5':
932
+ case 'div6':
933
+ $info['video']['dataformat'] = 'divx';
934
+ break;
935
 
936
+ default:
937
+ // do nothing
938
+ break;
939
+ }
940
+ unset($atom_structure['sample_description_table'][$i]['data']);
941
  }
942
+ break;
 
 
943
 
944
 
945
+ case 'stts': // Sample Table Time-to-Sample atom
946
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
947
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
948
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
949
+ $sttsEntriesDataOffset = 8;
950
+ //$FrameRateCalculatorArray = array();
951
+ $frames_count = 0;
952
 
953
+ $max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
954
+ if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
955
+ $this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($this->getid3->memory_limit / 1048576).'MB).');
956
+ }
957
+ for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
958
+ $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
959
+ $sttsEntriesDataOffset += 4;
960
+ $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
961
+ $sttsEntriesDataOffset += 4;
962
+
963
+ $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
964
+
965
+ // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
966
+ //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
967
+ // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
968
+ // if ($stts_new_framerate <= 60) {
969
+ // // some atoms have durations of "1" giving a very large framerate, which probably is not right
970
+ // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
971
+ // }
972
+ //}
973
+ //
974
+ //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
975
+ }
976
+ $info['quicktime']['stts_framecount'][] = $frames_count;
977
+ //$sttsFramesTotal = 0;
978
+ //$sttsSecondsTotal = 0;
979
+ //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
980
+ // if (($frames_per_second > 60) || ($frames_per_second < 1)) {
981
+ // // not video FPS information, probably audio information
982
+ // $sttsFramesTotal = 0;
983
+ // $sttsSecondsTotal = 0;
984
+ // break;
985
  // }
986
+ // $sttsFramesTotal += $frame_count;
987
+ // $sttsSecondsTotal += $frame_count / $frames_per_second;
988
  //}
989
+ //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
990
+ // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
991
+ // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
992
+ // }
993
+ //}
994
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
995
 
996
 
997
+ case 'stss': // Sample Table Sync Sample (key frames) atom
998
+ if ($ParseAllPossibleAtoms) {
999
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1000
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1001
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1002
+ $stssEntriesDataOffset = 8;
1003
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1004
+ $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
1005
+ $stssEntriesDataOffset += 4;
1006
+ }
1007
  }
1008
+ break;
 
1009
 
1010
 
1011
+ case 'stsc': // Sample Table Sample-to-Chunk atom
1012
+ if ($ParseAllPossibleAtoms) {
1013
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1014
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1015
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1016
+ $stscEntriesDataOffset = 8;
1017
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1018
+ $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1019
+ $stscEntriesDataOffset += 4;
1020
+ $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1021
+ $stscEntriesDataOffset += 4;
1022
+ $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1023
+ $stscEntriesDataOffset += 4;
1024
+ }
1025
  }
1026
+ break;
 
1027
 
1028
 
1029
+ case 'stsz': // Sample Table SiZe atom
1030
+ if ($ParseAllPossibleAtoms) {
1031
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1032
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1033
+ $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1034
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1035
+ $stszEntriesDataOffset = 12;
1036
+ if ($atom_structure['sample_size'] == 0) {
1037
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1038
+ $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
1039
+ $stszEntriesDataOffset += 4;
1040
+ }
1041
+ }
1042
+ }
1043
+ break;
1044
+
1045
+
1046
+ case 'stco': // Sample Table Chunk Offset atom
1047
+ if ($ParseAllPossibleAtoms) {
1048
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1049
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1050
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1051
+ $stcoEntriesDataOffset = 8;
1052
  for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1053
+ $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
1054
+ $stcoEntriesDataOffset += 4;
1055
  }
1056
  }
1057
+ break;
 
1058
 
1059
 
1060
+ case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
1061
+ if ($ParseAllPossibleAtoms) {
1062
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1063
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1064
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1065
+ $stcoEntriesDataOffset = 8;
1066
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1067
+ $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
1068
+ $stcoEntriesDataOffset += 8;
1069
+ }
1070
  }
1071
+ break;
 
1072
 
1073
 
1074
+ case 'dref': // Data REFerence atom
 
1075
  $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1076
  $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1077
  $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1078
+ $drefDataOffset = 8;
1079
  for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1080
+ $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
1081
+ $drefDataOffset += 4;
1082
+ $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
1083
+ $drefDataOffset += 4;
1084
+ $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
1085
+ $drefDataOffset += 1;
1086
+ $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000
1087
+ $drefDataOffset += 3;
1088
+ $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
1089
+ $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
1090
+
1091
+ $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
1092
  }
1093
+ break;
 
1094
 
1095
 
1096
+ case 'gmin': // base Media INformation atom
1097
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1098
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1099
+ $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
1100
+ $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
1101
+ $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
1102
+ $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
1103
+ $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
1104
+ $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
1105
+ break;
 
 
 
 
 
 
 
 
 
 
1106
 
1107
 
1108
+ case 'smhd': // Sound Media information HeaDer atom
1109
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1110
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1111
+ $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
1112
+ $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
1113
+ break;
 
 
 
 
1114
 
1115
 
1116
+ case 'vmhd': // Video Media information HeaDer atom
1117
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1118
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1119
+ $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
1120
+ $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
1121
+ $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
1122
+ $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
1123
 
1124
+ $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
1125
+ break;
1126
 
 
 
 
 
 
 
 
1127
 
1128
+ case 'hdlr': // HanDLeR reference atom
1129
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1130
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1131
+ $atom_structure['component_type'] = substr($atom_data, 4, 4);
1132
+ $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
1133
+ $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
1134
+ $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1135
+ $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1136
+ $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
1137
 
1138
+ if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
1139
+ $info['video']['dataformat'] = 'quicktimevr';
1140
+ }
1141
+ break;
1142
 
 
 
 
 
 
 
 
 
 
1143
 
1144
+ case 'mdhd': // MeDia HeaDer atom
1145
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1146
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1147
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1148
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1149
+ $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1150
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1151
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
1152
+ $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
1153
 
1154
+ if ($atom_structure['time_scale'] == 0) {
1155
+ $this->error('Corrupt Quicktime file: mdhd.time_scale == zero');
1156
+ return false;
1157
+ }
1158
+ $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1159
 
1160
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1161
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1162
+ $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
1163
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
1164
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
1165
+ $info['comments']['language'][] = $atom_structure['language'];
1166
+ }
1167
+ break;
 
1168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1169
 
1170
+ case 'pnot': // Preview atom
1171
+ $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"
1172
+ $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00
1173
+ $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
1174
+ $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
1175
 
1176
+ $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
1177
+ break;
 
 
 
1178
 
 
 
1179
 
1180
+ case 'crgn': // Clipping ReGioN atom
1181
+ $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box,
1182
+ $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields
1183
+ $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
1184
+ break;
1185
 
 
 
 
 
 
1186
 
1187
+ case 'load': // track LOAD settings atom
1188
+ $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
1189
+ $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1190
+ $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1191
+ $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1192
 
1193
+ $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
1194
+ $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
1195
+ break;
 
 
1196
 
 
 
 
1197
 
1198
+ case 'tmcd': // TiMe CoDe atom
1199
+ case 'chap': // CHAPter list atom
1200
+ case 'sync': // SYNChronization atom
1201
+ case 'scpt': // tranSCriPT atom
1202
+ case 'ssrc': // non-primary SouRCe atom
1203
+ for ($i = 0; $i < strlen($atom_data); $i += 4) {
1204
+ @$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1205
+ }
1206
+ break;
1207
 
 
 
 
 
 
 
 
 
 
1208
 
1209
+ case 'elst': // Edit LiST atom
1210
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1211
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1212
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1213
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
1214
+ $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
1215
+ $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
1216
+ $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
1217
+ }
1218
+ break;
1219
 
 
 
 
 
 
 
 
 
 
 
1220
 
1221
+ case 'kmat': // compressed MATte atom
1222
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1223
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
1224
+ $atom_structure['matte_data_raw'] = substr($atom_data, 4);
1225
+ break;
1226
 
 
 
 
 
 
1227
 
1228
+ case 'ctab': // Color TABle atom
1229
+ $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000
1230
+ $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000
1231
+ $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1;
1232
+ for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
1233
+ $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
1234
+ $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
1235
+ $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
1236
+ $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
1237
+ }
1238
+ break;
1239
 
 
 
 
 
 
 
 
 
 
 
 
1240
 
1241
+ case 'mvhd': // MoVie HeaDer atom
1242
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1243
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1244
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1245
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1246
+ $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1247
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1248
+ $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
1249
+ $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
1250
+ $atom_structure['reserved'] = substr($atom_data, 26, 10);
1251
+ $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
1252
+ $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1253
+ $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
1254
+ $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
1255
+ $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1256
+ $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
1257
+ $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
1258
+ $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1259
+ $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
1260
+ $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
1261
+ $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
1262
+ $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
1263
+ $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
1264
+ $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
1265
+ $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
1266
+ $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
1267
+
1268
+ if ($atom_structure['time_scale'] == 0) {
1269
+ $this->error('Corrupt Quicktime file: mvhd.time_scale == zero');
1270
+ return false;
1271
+ }
1272
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1273
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1274
+ $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1275
+ $info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
1276
+ $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
1277
+ break;
1278
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1279
 
1280
+ case 'tkhd': // TracK HeaDer atom
1281
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1282
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1283
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1284
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
1285
+ $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1286
+ $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1287
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1288
+ $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
1289
+ $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
1290
+ $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
1291
+ $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
1292
+ $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
1293
+ // http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
1294
+ // http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
1295
+ $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1296
+ $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
1297
+ $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
1298
+ $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1299
+ $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
1300
+ $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
1301
+ $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1302
+ $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
1303
+ $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
1304
+ $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
1305
+ $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
1306
+ $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001);
1307
+ $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002);
1308
+ $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
1309
+ $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008);
1310
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1311
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1312
+
1313
+ // https://www.getid3.org/phpBB3/viewtopic.php?t=1908
1314
+ // attempt to compute rotation from matrix values
1315
+ // 2017-Dec-28: uncertain if 90/270 are correctly oriented; values returned by FixedPoint16_16 should perhaps be -1 instead of 65535(?)
1316
+ $matrixRotation = 0;
1317
+ switch ($atom_structure['matrix_a'].':'.$atom_structure['matrix_b'].':'.$atom_structure['matrix_c'].':'.$atom_structure['matrix_d']) {
1318
+ case '1:0:0:1': $matrixRotation = 0; break;
1319
+ case '0:1:65535:0': $matrixRotation = 90; break;
1320
+ case '65535:0:0:65535': $matrixRotation = 180; break;
1321
+ case '0:65535:1:0': $matrixRotation = 270; break;
1322
+ default: break;
1323
+ }
1324
 
1325
+ // https://www.getid3.org/phpBB3/viewtopic.php?t=2468
1326
+ // The rotation matrix can appear in the Quicktime file multiple times, at least once for each track,
1327
+ // and it's possible that only the video track (or, in theory, one of the video tracks) is flagged as
1328
+ // rotated while the other tracks (e.g. audio) is tagged as rotation=0 (behavior noted on iPhone 8 Plus)
1329
+ // The correct solution would be to check if the TrackID associated with the rotation matrix is indeed
1330
+ // a video track (or the main video track) and only set the rotation then, but since information about
1331
+ // what track is what is not trivially there to be examined, the lazy solution is to set the rotation
1332
+ // if it is found to be nonzero, on the assumption that tracks that don't need it will have rotation set
1333
+ // to zero (and be effectively ignored) and the video track will have rotation set correctly, which will
1334
+ // either be zero and automatically correct, or nonzero and be set correctly.
1335
+ if (!isset($info['video']['rotate']) || (($info['video']['rotate'] == 0) && ($matrixRotation > 0))) {
1336
+ $info['quicktime']['video']['rotate'] = $info['video']['rotate'] = $matrixRotation;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1337
  }
1338
+
1339
+ if ($atom_structure['flags']['enabled'] == 1) {
1340
+ if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
1341
+ $info['video']['resolution_x'] = $atom_structure['width'];
1342
+ $info['video']['resolution_y'] = $atom_structure['height'];
1343
+ }
1344
+ $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
1345
+ $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
1346
+ $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
1347
+ $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
1348
+ } else {
1349
+ // see: https://www.getid3.org/phpBB3/viewtopic.php?t=1295
1350
+ //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
1351
+ //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
1352
+ //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); }
1353
+ }
1354
+ break;
1355
 
1356
 
1357
+ case 'iods': // Initial Object DeScriptor atom
1358
+ // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
1359
+ // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
1360
+ $offset = 0;
1361
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1362
+ $offset += 1;
1363
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
1364
+ $offset += 3;
1365
+ $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1366
  $offset += 1;
1367
+ $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1368
  //$offset already adjusted by quicktime_read_mp4_descr_length()
1369
+ $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
1370
+ $offset += 2;
1371
+ $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1372
+ $offset += 1;
1373
+ $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1374
+ $offset += 1;
1375
+ $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1376
+ $offset += 1;
1377
+ $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1378
+ $offset += 1;
1379
+ $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1380
+ $offset += 1;
1381
 
1382
+ $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
1383
+ for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) {
1384
+ $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1385
+ $offset += 1;
1386
+ $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1387
+ //$offset already adjusted by quicktime_read_mp4_descr_length()
1388
+ $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
1389
+ $offset += 4;
1390
+ }
1391
 
1392
+ $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
1393
+ $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
1394
+ break;
1395
+
1396
+ case 'ftyp': // FileTYPe (?) atom (for MP4 it seems)
1397
+ $atom_structure['signature'] = substr($atom_data, 0, 4);
1398
+ $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1399
+ $atom_structure['fourcc'] = substr($atom_data, 8, 4);
1400
+ break;
1401
 
1402
+ case 'mdat': // Media DATa atom
1403
+ // 'mdat' contains the actual data for the audio/video, possibly also subtitles
1404
 
1405
+ /* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to info@getid3.org */
1406
 
1407
+ // first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?)
1408
+ $mdat_offset = 0;
1409
+ while (true) {
1410
+ if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') {
1411
+ $mdat_offset += 8;
1412
+ } elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') {
1413
+ $mdat_offset += 8;
1414
+ } else {
1415
+ break;
1416
+ }
1417
+ }
1418
+ if (substr($atom_data, $mdat_offset, 4) == 'GPRO') {
1419
+ $GOPRO_chunk_length = getid3_lib::LittleEndian2Int(substr($atom_data, $mdat_offset + 4, 4));
1420
+ $GOPRO_offset = 8;
1421
+ $atom_structure['GPRO']['raw'] = substr($atom_data, $mdat_offset + 8, $GOPRO_chunk_length - 8);
1422
+ $atom_structure['GPRO']['firmware'] = substr($atom_structure['GPRO']['raw'], 0, 15);
1423
+ $atom_structure['GPRO']['unknown1'] = substr($atom_structure['GPRO']['raw'], 15, 16);
1424
+ $atom_structure['GPRO']['unknown2'] = substr($atom_structure['GPRO']['raw'], 31, 32);
1425
+ $atom_structure['GPRO']['unknown3'] = substr($atom_structure['GPRO']['raw'], 63, 16);
1426
+ $atom_structure['GPRO']['camera'] = substr($atom_structure['GPRO']['raw'], 79, 32);
1427
+ $info['quicktime']['camera']['model'] = rtrim($atom_structure['GPRO']['camera'], "\x00");
1428
  }
 
1429
 
1430
+ // check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
1431
+ while (($mdat_offset < (strlen($atom_data) - 8))
1432
+ && ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
1433
+ && ($chapter_string_length < 1000)
1434
+ && ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
1435
+ && preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) {
1436
+ list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches;
1437
+ $mdat_offset += (2 + $chapter_string_length);
1438
+ @$info['quicktime']['comments']['chapters'][] = $chapter_string;
1439
+
1440
+ // "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled)
1441
+ if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8
1442
+ $mdat_offset += 12;
1443
+ }
1444
+ }
1445
 
1446
+ if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
1447
+
1448
+ $info['avdataoffset'] = $atom_structure['offset'] + 8; // $info['quicktime'][$atomname]['offset'] + 8;
1449
+ $OldAVDataEnd = $info['avdataend'];
1450
+ $info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
1451
+
1452
+ $getid3_temp = new getID3();
1453
+ $getid3_temp->openfile($this->getid3->filename);
1454
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1455
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
1456
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
1457
+ if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) {
1458
+ $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1459
+ if (!empty($getid3_temp->info['warning'])) {
1460
+ foreach ($getid3_temp->info['warning'] as $value) {
1461
+ $this->warning($value);
1462
+ }
1463
+ }
1464
+ if (!empty($getid3_temp->info['mpeg'])) {
1465
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
1466
+ if (isset($info['mpeg']['audio'])) {
1467
+ $info['audio']['dataformat'] = 'mp3';
1468
+ $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
1469
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
1470
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
1471
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
1472
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1473
+ $info['bitrate'] = $info['audio']['bitrate'];
1474
+ }
1475
+ }
1476
+ }
1477
+ unset($getid3_mp3, $getid3_temp);
1478
+ $info['avdataend'] = $OldAVDataEnd;
1479
+ unset($OldAVDataEnd);
1480
 
1481
+ }
1482
 
1483
+ unset($mdat_offset, $chapter_string_length, $chapter_matches);
1484
+ break;
1485
 
1486
+ case 'free': // FREE space atom
1487
+ case 'skip': // SKIP atom
1488
+ case 'wide': // 64-bit expansion placeholder atom
1489
+ // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
1490
+
1491
+ // When writing QuickTime files, it is sometimes necessary to update an atom's size.
1492
+ // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
1493
+ // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
1494
+ // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
1495
+ // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
1496
+ // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
1497
+ // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
1498
+ break;
1499
 
1500
+
1501
+ case 'nsav': // NoSAVe atom
1502
+ // http://developer.apple.com/technotes/tn/tn2038.html
1503
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
1504
+ break;
1505
+
1506
+ case 'ctyp': // Controller TYPe atom (seen on QTVR)
1507
+ // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
1508
+ // some controller names are:
1509
+ // 0x00 + 'std' for linear movie
1510
+ // 'none' for no controls
1511
+ $atom_structure['ctyp'] = substr($atom_data, 0, 4);
1512
+ $info['quicktime']['controller'] = $atom_structure['ctyp'];
1513
+ switch ($atom_structure['ctyp']) {
1514
+ case 'qtvr':
1515
+ $info['video']['dataformat'] = 'quicktimevr';
1516
+ break;
1517
+ }
1518
+ break;
1519
+
1520
+ case 'pano': // PANOrama track (seen on QTVR)
1521
+ $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
1522
+ break;
1523
+
1524
+ case 'hint': // HINT track
1525
+ case 'hinf': //
1526
+ case 'hinv': //
1527
+ case 'hnti': //
1528
+ $info['quicktime']['hinting'] = true;
1529
+ break;
1530
+
1531
+ case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
1532
+ for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
1533
+ $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1534
+ }
1535
+ break;
1536
+
1537
+
1538
+ // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
1539
+ case 'FXTC': // Something to do with Adobe After Effects (?)
1540
+ case 'PrmA':
1541
+ case 'code':
1542
+ case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
1543
+ case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
1544
+ // tapt seems to be used to compute the video size [https://www.getid3.org/phpBB3/viewtopic.php?t=838]
1545
+ // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
1546
+ // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
1547
+ case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1548
+ case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1549
+ case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1550
+ case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1551
+ //$atom_structure['data'] = $atom_data;
1552
+ break;
1553
+
1554
+ case "\xA9".'xyz': // GPS latitude+longitude+altitude
1555
+ $atom_structure['data'] = $atom_data;
1556
+ if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
1557
+ @list($all, $latitude, $longitude, $altitude) = $matches;
1558
+ $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude);
1559
+ $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
1560
+ if (!empty($altitude)) {
1561
+ $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
1562
  }
1563
+ } else {
1564
+ $this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.');
1565
  }
1566
+ break;
 
 
1567
 
1568
+ case 'NCDT':
1569
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1570
+ // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
1571
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1572
+ break;
1573
+ case 'NCTH': // Nikon Camera THumbnail image
1574
+ case 'NCVW': // Nikon Camera preVieW image
1575
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1576
+ if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
1577
+ $atom_structure['data'] = $atom_data;
1578
+ $atom_structure['image_mime'] = 'image/jpeg';
1579
+ $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
1580
+ $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
1581
+ }
1582
+ break;
1583
+ case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1584
+ $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
1585
+ break;
1586
+ case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1587
+ case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1588
+ case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
1589
+ $atom_structure['data'] = $atom_data;
1590
+ break;
1591
 
1592
+ case "\x00\x00\x00\x00":
1593
+ // some kind of metacontainer, may contain a big data dump such as:
1594
+ // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
1595
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
1596
 
1597
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1598
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1599
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1600
+ //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1601
+ break;
 
 
 
 
 
 
 
 
1602
 
1603
+ case 'meta': // METAdata atom
1604
+ // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
1605
 
1606
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1607
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1608
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1609
+ break;
1610
 
1611
+ case 'data': // metaDATA atom
1612
+ static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other
1613
+ // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
1614
+ $atom_structure['language'] = substr($atom_data, 4 + 0, 2);
1615
+ $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
1616
+ $atom_structure['data'] = substr($atom_data, 4 + 4);
1617
+ $atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];
 
 
 
 
 
 
1618
 
1619
+ if ($atom_structure['key_name'] && $atom_structure['data']) {
1620
+ @$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data'];
1621
+ }
1622
+ break;
1623
 
1624
+ case 'keys': // KEYS that may be present in the metadata atom.
1625
+ // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21
1626
+ // The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom.
1627
+ // This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys".
1628
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1629
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1630
+ $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
1631
+ $keys_atom_offset = 8;
1632
+ for ($i = 1; $i <= $atom_structure['entry_count']; $i++) {
1633
+ $atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4));
1634
+ $atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4);
1635
+ $atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8);
1636
+ $keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace
1637
+
1638
+ $info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value'];
1639
+ }
1640
+ break;
1641
 
1642
+ case 'gps ':
1643
+ // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
1644
+ // The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data.
1645
+ // The first row is version/metadata/notsure, I skip that.
1646
+ // The following rows consist of 4byte address (absolute) and 4byte size (0x1000), these point to the GPS data in the file.
1647
+
1648
+ $GPS_rowsize = 8; // 4 bytes for offset, 4 bytes for size
1649
+ if (strlen($atom_data) > 0) {
1650
+ if ((strlen($atom_data) % $GPS_rowsize) == 0) {
1651
+ $atom_structure['gps_toc'] = array();
1652
+ foreach (str_split($atom_data, $GPS_rowsize) as $counter => $datapair) {
1653
+ $atom_structure['gps_toc'][] = unpack('Noffset/Nsize', substr($atom_data, $counter * $GPS_rowsize, $GPS_rowsize));
1654
+ }
1655
 
1656
+ $atom_structure['gps_entries'] = array();
1657
+ $previous_offset = $this->ftell();
1658
+ foreach ($atom_structure['gps_toc'] as $key => $gps_pointer) {
1659
+ if ($key == 0) {
1660
+ // "The first row is version/metadata/notsure, I skip that."
1661
+ continue;
1662
+ }
1663
+ $this->fseek($gps_pointer['offset']);
1664
+ $GPS_free_data = $this->fread($gps_pointer['size']);
1665
+
1666
+ /*
1667
+ // 2017-05-10: I see some of the data, notably the Hour-Minute-Second, but cannot reconcile the rest of the data. However, the NMEA "GPRMC" line is there and relatively easy to parse, so I'm using that instead
1668
+
1669
+ // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
1670
+ // The structure of the GPS data atom (the 'free' atoms mentioned above) is following:
1671
+ // hour,minute,second,year,month,day,active,latitude_b,longitude_b,unknown2,latitude,longitude,speed = struct.unpack_from('<IIIIIIssssfff',data, 48)
1672
+ // For those unfamiliar with python struct:
1673
+ // I = int
1674
+ // s = is string (size 1, in this case)
1675
+ // f = float
1676
+
1677
+ //$atom_structure['gps_entries'][$key] = unpack('Vhour/Vminute/Vsecond/Vyear/Vmonth/Vday/Vactive/Vlatitude_b/Vlongitude_b/Vunknown2/flatitude/flongitude/fspeed', substr($GPS_free_data, 48));
1678
+ */
1679
+
1680
+ // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
1681
+ // $GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67
1682
+ // $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F
1683
+ // $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D
1684
+ if (preg_match('#\\$GPRMC,([0-9\\.]*),([AV]),([0-9\\.]*),([NS]),([0-9\\.]*),([EW]),([0-9\\.]*),([0-9\\.]*),([0-9]*),([0-9\\.]*),([EW]?)(,[A])?(\\*[0-9A-F]{2})#', $GPS_free_data, $matches)) {
1685
+ $GPS_this_GPRMC = array();
1686
+ list(
1687
+ $GPS_this_GPRMC['raw']['gprmc'],
1688
+ $GPS_this_GPRMC['raw']['timestamp'],
1689
+ $GPS_this_GPRMC['raw']['status'],
1690
+ $GPS_this_GPRMC['raw']['latitude'],
1691
+ $GPS_this_GPRMC['raw']['latitude_direction'],
1692
+ $GPS_this_GPRMC['raw']['longitude'],
1693
+ $GPS_this_GPRMC['raw']['longitude_direction'],
1694
+ $GPS_this_GPRMC['raw']['knots'],
1695
+ $GPS_this_GPRMC['raw']['angle'],
1696
+ $GPS_this_GPRMC['raw']['datestamp'],
1697
+ $GPS_this_GPRMC['raw']['variation'],
1698
+ $GPS_this_GPRMC['raw']['variation_direction'],
1699
+ $dummy,
1700
+ $GPS_this_GPRMC['raw']['checksum'],
1701
+ ) = $matches;
1702
+
1703
+ $hour = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2);
1704
+ $minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2);
1705
+ $second = substr($GPS_this_GPRMC['raw']['timestamp'], 4, 2);
1706
+ $ms = substr($GPS_this_GPRMC['raw']['timestamp'], 6); // may contain decimal seconds
1707
+ $day = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2);
1708
+ $month = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2);
1709
+ $year = substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2);
1710
+ $year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess
1711
+ $GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms;
1712
+
1713
+ $GPS_this_GPRMC['active'] = ($GPS_this_GPRMC['raw']['status'] == 'A'); // A=Active,V=Void
1714
+
1715
+ foreach (array('latitude','longitude') as $latlon) {
1716
+ preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches);
1717
+ list($dummy, $deg, $min) = $matches;
1718
+ $GPS_this_GPRMC[$latlon] = $deg + ($min / 60);
1719
+ }
1720
+ $GPS_this_GPRMC['latitude'] *= (($GPS_this_GPRMC['raw']['latitude_direction'] == 'S') ? -1 : 1);
1721
+ $GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1);
1722
+
1723
+ $GPS_this_GPRMC['heading'] = $GPS_this_GPRMC['raw']['angle'];
1724
+ $GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots'];
1725
+ $GPS_this_GPRMC['speed_kmh'] = $GPS_this_GPRMC['raw']['knots'] * 1.852;
1726
+ if ($GPS_this_GPRMC['raw']['variation']) {
1727
+ $GPS_this_GPRMC['variation'] = $GPS_this_GPRMC['raw']['variation'];
1728
+ $GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1);
1729
+ }
1730
 
1731
+ $atom_structure['gps_entries'][$key] = $GPS_this_GPRMC;
1732
+
1733
+ @$info['quicktime']['gps_track'][$GPS_this_GPRMC['timestamp']] = array(
1734
+ 'latitude' => (float) $GPS_this_GPRMC['latitude'],
1735
+ 'longitude' => (float) $GPS_this_GPRMC['longitude'],
1736
+ 'speed_kmh' => (float) $GPS_this_GPRMC['speed_kmh'],
1737
+ 'heading' => (float) $GPS_this_GPRMC['heading'],
1738
+ );
 
 
 
 
 
 
 
1739
 
1740
+ } else {
1741
+ $this->warning('Unhandled GPS format in "free" atom at offset '.$gps_pointer['offset']);
1742
+ }
1743
+ }
1744
+ $this->fseek($previous_offset);
1745
+
1746
+ } else {
1747
+ $this->warning('QuickTime atom "'.$atomname.'" is not mod-8 bytes long ('.$atomsize.' bytes) at offset '.$baseoffset);
1748
+ }
1749
+ } else {
1750
+ $this->warning('QuickTime atom "'.$atomname.'" is zero bytes long at offset '.$baseoffset);
1751
  }
1752
+ break;
 
 
 
1753
 
1754
+ case 'loci':// 3GP location (El Loco)
1755
+ $loffset = 0;
1756
+ $info['quicktime']['comments']['gps_flags'] = array( getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)));
1757
+ $info['quicktime']['comments']['gps_lang'] = array( getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)));
1758
+ $info['quicktime']['comments']['gps_location'] = array( $this->LociString(substr($atom_data, 6), $loffset));
1759
+ $loci_data = substr($atom_data, 6 + $loffset);
1760
+ $info['quicktime']['comments']['gps_role'] = array( getid3_lib::BigEndian2Int(substr($loci_data, 0, 1)));
1761
+ $info['quicktime']['comments']['gps_longitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4)));
1762
+ $info['quicktime']['comments']['gps_latitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4)));
1763
+ $info['quicktime']['comments']['gps_altitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4)));
1764
+ $info['quicktime']['comments']['gps_body'] = array( $this->LociString(substr($loci_data, 13 ), $loffset));
1765
+ $info['quicktime']['comments']['gps_notes'] = array( $this->LociString(substr($loci_data, 13 + $loffset), $loffset));
1766
+ break;
 
 
 
 
 
 
 
 
 
 
1767
 
1768
+ case 'chpl': // CHaPter List
1769
+ // https://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf
1770
+ $chpl_version = getid3_lib::BigEndian2Int(substr($atom_data, 4, 1)); // Expected to be 0
1771
+ $chpl_flags = getid3_lib::BigEndian2Int(substr($atom_data, 5, 3)); // Reserved, set to 0
1772
+ $chpl_count = getid3_lib::BigEndian2Int(substr($atom_data, 8, 1));
1773
+ $chpl_offset = 9;
1774
+ for ($i = 0; $i < $chpl_count; $i++) {
1775
+ if (($chpl_offset + 9) >= strlen($atom_data)) {
1776
+ $this->warning('QuickTime chapter '.$i.' extends beyond end of "chpl" atom');
1777
+ break;
1778
+ }
1779
+ $info['quicktime']['chapters'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 8)) / 10000000; // timestamps are stored as 100-nanosecond units
1780
+ $chpl_offset += 8;
1781
+ $chpl_title_size = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 1));
1782
+ $chpl_offset += 1;
1783
+ $info['quicktime']['chapters'][$i]['title'] = substr($atom_data, $chpl_offset, $chpl_title_size);
1784
+ $chpl_offset += $chpl_title_size;
1785
+ }
1786
+ break;
1787
 
1788
+ case 'FIRM': // FIRMware version(?), seen on GoPro Hero4
1789
+ $info['quicktime']['camera']['firmware'] = $atom_data;
1790
+ break;
 
 
1791
 
1792
+ case 'CAME': // FIRMware version(?), seen on GoPro Hero4
1793
+ $info['quicktime']['camera']['serial_hash'] = unpack('H*', $atom_data);
1794
+ break;
 
 
 
1795
 
1796
+ case 'dscp':
1797
+ case 'rcif':
1798
+ // https://www.getid3.org/phpBB3/viewtopic.php?t=1908
1799
+ if (substr($atom_data, 0, 7) == "\x00\x00\x00\x00\x55\xC4".'{') {
1800
+ if ($json_decoded = @json_decode(rtrim(substr($atom_data, 6), "\x00"), true)) {
1801
+ $info['quicktime']['camera'][$atomname] = $json_decoded;
1802
+ if (($atomname == 'rcif') && isset($info['quicktime']['camera']['rcif']['wxcamera']['rotate'])) {
1803
+ $info['video']['rotate'] = $info['quicktime']['video']['rotate'] = $info['quicktime']['camera']['rcif']['wxcamera']['rotate'];
1804
+ }
1805
+ } else {
1806
+ $this->warning('Failed to JSON decode atom "'.$atomname.'"');
1807
+ $atom_structure['data'] = $atom_data;
1808
+ }
1809
+ unset($json_decoded);
1810
+ } else {
1811
+ $this->warning('Expecting 55 C4 7B at start of atom "'.$atomname.'", found '.getid3_lib::PrintHexBytes(substr($atom_data, 4, 3)).' instead');
1812
+ $atom_structure['data'] = $atom_data;
1813
+ }
1814
+ break;
1815
+
1816
+ case 'frea':
1817
+ // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1818
+ // may contain "scra" (PreviewImage) and/or "thma" (ThumbnailImage)
1819
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1820
+ break;
1821
+ case 'tima': // subatom to "frea"
1822
+ // no idea what this does, the one sample file I've seen has a value of 0x00000027
1823
+ $atom_structure['data'] = $atom_data;
1824
+ break;
1825
+ case 'ver ': // subatom to "frea"
1826
+ // some kind of version number, the one sample file I've seen has a value of "3.00.073"
1827
+ $atom_structure['data'] = $atom_data;
1828
+ break;
1829
+ case 'thma': // subatom to "frea" -- "ThumbnailImage"
1830
+ // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1831
+ if (strlen($atom_data) > 0) {
1832
+ $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
1833
+ }
1834
+ break;
1835
+ case 'scra': // subatom to "frea" -- "PreviewImage"
1836
+ // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1837
+ // but the only sample file I've seen has no useful data here
1838
+ if (strlen($atom_data) > 0) {
1839
+ $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
1840
+ }
1841
+ break;
1842
+
1843
+
1844
+ default:
1845
+ $this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset);
1846
+ $atom_structure['data'] = $atom_data;
1847
+ break;
1848
+ }
1849
  }
1850
  array_pop($atomHierarchy);
1851
  return $atom_structure;
1852
  }
1853
 
1854
+ /**
1855
+ * @param string $atom_data
1856
+ * @param int $baseoffset
1857
+ * @param array $atomHierarchy
1858
+ * @param bool $ParseAllPossibleAtoms
1859
+ *
1860
+ * @return array|false
1861
+ */
1862
  public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
 
1863
  $atom_structure = false;
1864
  $subatomoffset = 0;
1865
  $subatomcounter = 0;
1874
  // Furthermore, for historical reasons the list of atoms is optionally
1875
  // terminated by a 32-bit integer set to 0. If you are writing a program
1876
  // to read user data atoms, you should allow for the terminating 0.
1877
+ if (strlen($atom_data) > 12) {
1878
+ $subatomoffset += 4;
1879
+ continue;
1880
+ }
1881
  return $atom_structure;
1882
  }
1883
+ $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
 
 
1884
  $subatomoffset += $subatomsize;
 
1885
  }
1886
  return $atom_structure;
1887
  }
1888
 
1889
+ /**
1890
+ * @param string $data
1891
+ * @param int $offset
1892
+ *
1893
+ * @return int
1894
+ */
1895
  public function quicktime_read_mp4_descr_length($data, &$offset) {
1896
  // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
1897
  $num_bytes = 0;
1903
  return $length;
1904
  }
1905
 
1906
+ /**
1907
+ * @param int $languageid
1908
+ *
1909
+ * @return string
1910
+ */
1911
  public function QuicktimeLanguageLookup($languageid) {
1912
  // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
1913
  static $QuicktimeLanguageLookup = array();
2045
  return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
2046
  }
2047
 
2048
+ /**
2049
+ * @param string $codecid
2050
+ *
2051
+ * @return string
2052
+ */
2053
  public function QuicktimeVideoCodecLookup($codecid) {
2054
  static $QuicktimeVideoCodecLookup = array();
2055
  if (empty($QuicktimeVideoCodecLookup)) {
2109
  return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
2110
  }
2111
 
2112
+ /**
2113
+ * @param string $codecid
2114
+ *
2115
+ * @return mixed|string
2116
+ */
2117
  public function QuicktimeAudioCodecLookup($codecid) {
2118
  static $QuicktimeAudioCodecLookup = array();
2119
  if (empty($QuicktimeAudioCodecLookup)) {
2159
  return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
2160
  }
2161
 
2162
+ /**
2163
+ * @param string $compressionid
2164
+ *
2165
+ * @return string
2166
+ */
2167
  public function QuicktimeDCOMLookup($compressionid) {
2168
  static $QuicktimeDCOMLookup = array();
2169
  if (empty($QuicktimeDCOMLookup)) {
2173
  return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
2174
  }
2175
 
2176
+ /**
2177
+ * @param int $colordepthid
2178
+ *
2179
+ * @return string
2180
+ */
2181
  public function QuicktimeColorNameLookup($colordepthid) {
2182
  static $QuicktimeColorNameLookup = array();
2183
  if (empty($QuicktimeColorNameLookup)) {
2196
  return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
2197
  }
2198
 
2199
+ /**
2200
+ * @param int $stik
2201
+ *
2202
+ * @return string
2203
+ */
2204
  public function QuicktimeSTIKLookup($stik) {
2205
  static $QuicktimeSTIKLookup = array();
2206
  if (empty($QuicktimeSTIKLookup)) {
2218
  return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
2219
  }
2220
 
2221
+ /**
2222
+ * @param int $audio_profile_id
2223
+ *
2224
+ * @return string
2225
+ */
2226
  public function QuicktimeIODSaudioProfileName($audio_profile_id) {
2227
  static $QuicktimeIODSaudioProfileNameLookup = array();
2228
  if (empty($QuicktimeIODSaudioProfileNameLookup)) {
2229
  $QuicktimeIODSaudioProfileNameLookup = array(
2230
+ 0x00 => 'ISO Reserved (0x00)',
2231
+ 0x01 => 'Main Audio Profile @ Level 1',
2232
+ 0x02 => 'Main Audio Profile @ Level 2',
2233
+ 0x03 => 'Main Audio Profile @ Level 3',
2234
+ 0x04 => 'Main Audio Profile @ Level 4',
2235
+ 0x05 => 'Scalable Audio Profile @ Level 1',
2236
+ 0x06 => 'Scalable Audio Profile @ Level 2',
2237
+ 0x07 => 'Scalable Audio Profile @ Level 3',
2238
+ 0x08 => 'Scalable Audio Profile @ Level 4',
2239
+ 0x09 => 'Speech Audio Profile @ Level 1',
2240
+ 0x0A => 'Speech Audio Profile @ Level 2',
2241
+ 0x0B => 'Synthetic Audio Profile @ Level 1',
2242
+ 0x0C => 'Synthetic Audio Profile @ Level 2',
2243
+ 0x0D => 'Synthetic Audio Profile @ Level 3',
2244
+ 0x0E => 'High Quality Audio Profile @ Level 1',
2245
+ 0x0F => 'High Quality Audio Profile @ Level 2',
2246
+ 0x10 => 'High Quality Audio Profile @ Level 3',
2247
+ 0x11 => 'High Quality Audio Profile @ Level 4',
2248
+ 0x12 => 'High Quality Audio Profile @ Level 5',
2249
+ 0x13 => 'High Quality Audio Profile @ Level 6',
2250
+ 0x14 => 'High Quality Audio Profile @ Level 7',
2251
+ 0x15 => 'High Quality Audio Profile @ Level 8',
2252
+ 0x16 => 'Low Delay Audio Profile @ Level 1',
2253
+ 0x17 => 'Low Delay Audio Profile @ Level 2',
2254
+ 0x18 => 'Low Delay Audio Profile @ Level 3',
2255
+ 0x19 => 'Low Delay Audio Profile @ Level 4',
2256
+ 0x1A => 'Low Delay Audio Profile @ Level 5',
2257
+ 0x1B => 'Low Delay Audio Profile @ Level 6',
2258
+ 0x1C => 'Low Delay Audio Profile @ Level 7',
2259
+ 0x1D => 'Low Delay Audio Profile @ Level 8',
2260
+ 0x1E => 'Natural Audio Profile @ Level 1',
2261
+ 0x1F => 'Natural Audio Profile @ Level 2',
2262
+ 0x20 => 'Natural Audio Profile @ Level 3',
2263
+ 0x21 => 'Natural Audio Profile @ Level 4',
2264
+ 0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
2265
+ 0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
2266
+ 0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
2267
+ 0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
2268
+ 0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
2269
+ 0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
2270
+ 0x28 => 'AAC Profile @ Level 1',
2271
+ 0x29 => 'AAC Profile @ Level 2',
2272
+ 0x2A => 'AAC Profile @ Level 4',
2273
+ 0x2B => 'AAC Profile @ Level 5',
2274
+ 0x2C => 'High Efficiency AAC Profile @ Level 2',
2275
+ 0x2D => 'High Efficiency AAC Profile @ Level 3',
2276
+ 0x2E => 'High Efficiency AAC Profile @ Level 4',
2277
+ 0x2F => 'High Efficiency AAC Profile @ Level 5',
2278
+ 0xFE => 'Not part of MPEG-4 audio profiles',
2279
+ 0xFF => 'No audio capability required',
2280
  );
2281
  }
2282
  return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
2283
  }
2284
 
2285
+ /**
2286
+ * @param int $video_profile_id
2287
+ *
2288
+ * @return string
2289
+ */
2290
  public function QuicktimeIODSvideoProfileName($video_profile_id) {
2291
  static $QuicktimeIODSvideoProfileNameLookup = array();
2292
  if (empty($QuicktimeIODSvideoProfileNameLookup)) {
2358
  return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
2359
  }
2360
 
2361
+ /**
2362
+ * @param int $rtng
2363
+ *
2364
+ * @return string
2365
+ */
2366
  public function QuicktimeContentRatingLookup($rtng) {
2367
  static $QuicktimeContentRatingLookup = array();
2368
  if (empty($QuicktimeContentRatingLookup)) {
2373
  return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
2374
  }
2375
 
2376
+ /**
2377
+ * @param int $akid
2378
+ *
2379
+ * @return string
2380
+ */
2381
  public function QuicktimeStoreAccountTypeLookup($akid) {
2382
  static $QuicktimeStoreAccountTypeLookup = array();
2383
  if (empty($QuicktimeStoreAccountTypeLookup)) {
2387
  return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
2388
  }
2389
 
2390
+ /**
2391
+ * @param int $sfid
2392
+ *
2393
+ * @return string
2394
+ */
2395
  public function QuicktimeStoreFrontCodeLookup($sfid) {
2396
  static $QuicktimeStoreFrontCodeLookup = array();
2397
  if (empty($QuicktimeStoreFrontCodeLookup)) {
2421
  return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
2422
  }
2423
 
2424
+ /**
2425
+ * @param string $atom_data
2426
+ *
2427
+ * @return array
2428
+ */
2429
  public function QuicktimeParseNikonNCTG($atom_data) {
2430
  // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
2431
  // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
2468
  );
2469
 
2470
  $offset = 0;
2471
+ $data = null;
2472
  $datalength = strlen($atom_data);
2473
  $parsed = array();
2474
  while ($offset < $datalength) {
 
2475
  $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;
2476
  $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
2477
  $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
2526
  $offset += ($data_size * 2);
2527
  break;
2528
  default:
2529
+ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
2530
  break 2;
2531
  }
2532
 
2604
  return $parsed;
2605
  }
2606
 
2607
+ /**
2608
+ * @param string $keyname
2609
+ * @param string|array $data
2610
+ * @param string $boxname
2611
+ *
2612
+ * @return bool
2613
+ */
2614
  public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
2615
  static $handyatomtranslatorarray = array();
2616
  if (empty($handyatomtranslatorarray)) {
2707
  $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id';
2708
 
2709
  // http://age.hobba.nl/audio/tag_frame_reference.html
2710
+ $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
2711
+ $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
2712
  */
2713
  }
2714
  $info = &$this->getid3->info;
2734
  $data = array('data'=>$data, 'image_mime'=>$image_mime);
2735
  }
2736
  }
2737
+ $gooddata = array($data);
2738
+ if ($comment_key == 'genre') {
2739
+ // some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
2740
+ $gooddata = explode(';', $data);
2741
+ }
2742
+ foreach ($gooddata as $data) {
2743
+ $info['quicktime']['comments'][$comment_key][] = $data;
2744
+ }
2745
  }
2746
  return true;
2747
  }
2748
 
2749
+ /**
2750
+ * @param string $lstring
2751
+ * @param int $count
2752
+ *
2753
+ * @return string
2754
+ */
2755
+ public function LociString($lstring, &$count) {
2756
+ // Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM
2757
+ // Also need to return the number of bytes the string occupied so additional fields can be extracted
2758
+ $len = strlen($lstring);
2759
+ if ($len == 0) {
2760
+ $count = 0;
2761
+ return '';
2762
+ }
2763
+ if ($lstring[0] == "\x00") {
2764
+ $count = 1;
2765
+ return '';
2766
+ }
2767
+ // check for BOM
2768
+ if (($len > 2) && ((($lstring[0] == "\xFE") && ($lstring[1] == "\xFF")) || (($lstring[0] == "\xFF") && ($lstring[1] == "\xFE")))) {
2769
+ // UTF-16
2770
+ if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
2771
+ $count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000
2772
+ return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]);
2773
+ } else {
2774
+ return '';
2775
+ }
2776
+ }
2777
+ // UTF-8
2778
+ if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
2779
+ $count = strlen($lmatches[1]) + 1; //account for trailing \x00
2780
+ return $lmatches[1];
2781
+ }
2782
+ return '';
2783
+ }
2784
+
2785
+ /**
2786
+ * @param string $nullterminatedstring
2787
+ *
2788
+ * @return string
2789
+ */
2790
  public function NoNullString($nullterminatedstring) {
2791
  // remove the single null terminator on null terminated strings
2792
  if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
2795
  return $nullterminatedstring;
2796
  }
2797
 
2798
+ /**
2799
+ * @param string $pascalstring
2800
+ *
2801
+ * @return string
2802
+ */
2803
  public function Pascal2String($pascalstring) {
2804
  // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
2805
  return substr($pascalstring, 1);
2806
  }
2807
 
2808
+
2809
+ /**
2810
+ * Helper functions for m4b audiobook chapters
2811
+ * code by Steffen Hartmann 2015-Nov-08.
2812
+ *
2813
+ * @param array $info
2814
+ * @param string $tag
2815
+ * @param string $history
2816
+ * @param array $result
2817
+ */
2818
+ public function search_tag_by_key($info, $tag, $history, &$result) {
2819
+ foreach ($info as $key => $value) {
2820
+ $key_history = $history.'/'.$key;
2821
+ if ($key === $tag) {
2822
+ $result[] = array($key_history, $info);
2823
+ } else {
2824
+ if (is_array($value)) {
2825
+ $this->search_tag_by_key($value, $tag, $key_history, $result);
2826
+ }
2827
+ }
2828
+ }
2829
+ }
2830
+
2831
+ /**
2832
+ * @param array $info
2833
+ * @param string $k
2834
+ * @param string $v
2835
+ * @param string $history
2836
+ * @param array $result
2837
+ */
2838
+ public function search_tag_by_pair($info, $k, $v, $history, &$result) {
2839
+ foreach ($info as $key => $value) {
2840
+ $key_history = $history.'/'.$key;
2841
+ if (($key === $k) && ($value === $v)) {
2842
+ $result[] = array($key_history, $info);
2843
+ } else {
2844
+ if (is_array($value)) {
2845
+ $this->search_tag_by_pair($value, $k, $v, $key_history, $result);
2846
+ }
2847
+ }
2848
+ }
2849
+ }
2850
+
2851
+ /**
2852
+ * @param array $info
2853
+ *
2854
+ * @return array
2855
+ */
2856
+ public function quicktime_time_to_sample_table($info) {
2857
+ $res = array();
2858
+ $this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
2859
+ foreach ($res as $value) {
2860
+ $stbl_res = array();
2861
+ $this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
2862
+ if (count($stbl_res) > 0) {
2863
+ $stts_res = array();
2864
+ $this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res);
2865
+ if (count($stts_res) > 0) {
2866
+ return $stts_res[0][1]['time_to_sample_table'];
2867
+ }
2868
+ }
2869
+ }
2870
+ return array();
2871
+ }
2872
+
2873
+ /**
2874
+ * @param array $info
2875
+ *
2876
+ * @return int
2877
+ */
2878
+ public function quicktime_bookmark_time_scale($info) {
2879
+ $time_scale = '';
2880
+ $ts_prefix_len = 0;
2881
+ $res = array();
2882
+ $this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
2883
+ foreach ($res as $value) {
2884
+ $stbl_res = array();
2885
+ $this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
2886
+ if (count($stbl_res) > 0) {
2887
+ $ts_res = array();
2888
+ $this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
2889
+ foreach ($ts_res as $sub_value) {
2890
+ $prefix = substr($sub_value[0], 0, -12);
2891
+ if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) {
2892
+ $time_scale = $sub_value[1]['time_scale'];
2893
+ $ts_prefix_len = strlen($prefix);
2894
+ }
2895
+ }
2896
+ }
2897
+ }
2898
+ return $time_scale;
2899
+ }
2900
+ /*
2901
+ // END helper functions for m4b audiobook chapters
2902
+ */
2903
+
2904
+
2905
  }
lib/getid3/module.audio-video.real.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.real.php //
@@ -18,7 +18,9 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
18
 
19
  class getid3_real extends getid3_handler
20
  {
21
-
 
 
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
@@ -53,7 +55,7 @@ class getid3_real extends getid3_handler
53
  }
54
  return true;
55
  }
56
- $info['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org';
57
  unset($info['bitrate']);
58
  unset($info['playtime_seconds']);
59
  return false;
@@ -67,7 +69,7 @@ class getid3_real extends getid3_handler
67
  $thisfile_real_chunks_currentchunk['offset'] = $this->ftell() - 8;
68
  $thisfile_real_chunks_currentchunk['length'] = $ChunkSize;
69
  if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) {
70
- $info['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file';
71
  return false;
72
  }
73
 
@@ -98,7 +100,7 @@ class getid3_real extends getid3_handler
98
  break;
99
 
100
  default:
101
- //$info['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)';
102
  break;
103
 
104
  }
@@ -354,7 +356,7 @@ class getid3_real extends getid3_handler
354
  break;
355
 
356
  default:
357
- $info['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset'];
358
  break;
359
  }
360
  $ChunkCounter++;
@@ -370,7 +372,12 @@ class getid3_real extends getid3_handler
370
  return true;
371
  }
372
 
373
-
 
 
 
 
 
374
  public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
375
  // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
376
 
@@ -485,6 +492,12 @@ class getid3_real extends getid3_handler
485
  return true;
486
  }
487
 
 
 
 
 
 
 
488
  public function RealAudioCodecFourCClookup($fourcc, $bitrate) {
489
  static $RealAudioCodecFourCClookup = array();
490
  if (empty($RealAudioCodecFourCClookup)) {
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.real.php //
18
 
19
  class getid3_real extends getid3_handler
20
  {
21
+ /**
22
+ * @return bool
23
+ */
24
  public function Analyze() {
25
  $info = &$this->getid3->info;
26
 
55
  }
56
  return true;
57
  }
58
+ $this->error('There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org');
59
  unset($info['bitrate']);
60
  unset($info['playtime_seconds']);
61
  return false;
69
  $thisfile_real_chunks_currentchunk['offset'] = $this->ftell() - 8;
70
  $thisfile_real_chunks_currentchunk['length'] = $ChunkSize;
71
  if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) {
72
+ $this->warning('Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file');
73
  return false;
74
  }
75
 
100
  break;
101
 
102
  default:
103
+ //$this->warning('Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)');
104
  break;
105
 
106
  }
356
  break;
357
 
358
  default:
359
+ $this->warning('Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset']);
360
  break;
361
  }
362
  $ChunkCounter++;
372
  return true;
373
  }
374
 
375
+ /**
376
+ * @param string $OldRAheaderData
377
+ * @param array $ParsedArray
378
+ *
379
+ * @return bool
380
+ */
381
  public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
382
  // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
383
 
492
  return true;
493
  }
494
 
495
+ /**
496
+ * @param string $fourcc
497
+ * @param int $bitrate
498
+ *
499
+ * @return string
500
+ */
501
  public function RealAudioCodecFourCClookup($fourcc, $bitrate) {
502
  static $RealAudioCodecFourCClookup = array();
503
  if (empty($RealAudioCodecFourCClookup)) {
lib/getid3/module.audio-video.riff.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.riff.php //
@@ -27,10 +27,15 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE_
27
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
28
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
29
 
30
- class getid3_riff extends getid3_handler {
31
-
32
  protected $container = 'riff'; // default
33
 
 
 
 
 
 
34
  public function Analyze() {
35
  $info = &$this->getid3->info;
36
 
@@ -46,6 +51,7 @@ class getid3_riff extends getid3_handler {
46
  $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
47
  $thisfile_riff_audio = &$thisfile_riff['audio'];
48
  $thisfile_riff_video = &$thisfile_riff['video'];
 
49
 
50
  $Original['avdataoffset'] = $info['avdataoffset'];
51
  $Original['avdataend'] = $info['avdataend'];
@@ -190,7 +196,7 @@ class getid3_riff extends getid3_handler {
190
  $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
191
  $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
192
  if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
193
- $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
194
  return false;
195
  }
196
  $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
@@ -199,7 +205,7 @@ class getid3_riff extends getid3_handler {
199
 
200
  $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
201
  if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
202
- $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];
203
  }
204
  $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
205
 
@@ -302,10 +308,10 @@ class getid3_riff extends getid3_handler {
302
  list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
303
  $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
304
  } else {
305
- $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
306
  }
307
  } else {
308
- $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
309
  }
310
  $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
311
  $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
@@ -357,6 +363,7 @@ class getid3_riff extends getid3_handler {
357
  }
358
  $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
359
  $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
 
360
 
361
  $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
362
  $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
@@ -385,10 +392,10 @@ class getid3_riff extends getid3_handler {
385
  $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
386
 
387
  if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
388
- $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
389
  break;
390
  } elseif ($SNDM_thisTagSize <= 0) {
391
- $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
392
  break;
393
  }
394
  $SNDM_startoffset += $SNDM_thisTagSize;
@@ -397,7 +404,7 @@ class getid3_riff extends getid3_handler {
397
  if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
398
  $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
399
  } else {
400
- $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
401
  }
402
  }
403
 
@@ -405,7 +412,6 @@ class getid3_riff extends getid3_handler {
405
  'tracktitle'=>'title',
406
  'category' =>'genre',
407
  'cdtitle' =>'album',
408
- 'tracktitle'=>'title',
409
  );
410
  foreach ($tagmapping as $fromkey => $tokey) {
411
  if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
@@ -428,13 +434,15 @@ class getid3_riff extends getid3_handler {
428
  }
429
  if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
430
  $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
431
- $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
 
432
  $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
433
  $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
434
  $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
435
  $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
436
  $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
437
  $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
 
438
  }
439
  unset($parsedXML);
440
  }
@@ -570,7 +578,7 @@ class getid3_riff extends getid3_handler {
570
  // byte, in which case - skip warning
571
  } else {
572
  // Short by more than one byte, throw warning
573
- $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
574
  $info['avdataend'] = $info['filesize'];
575
  }
576
  break;
@@ -579,11 +587,11 @@ class getid3_riff extends getid3_handler {
579
  if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
580
  // output file appears to be incorrectly *not* padded to nearest WORD boundary
581
  // Output less severe warning
582
- $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
583
  $info['avdataend'] = $info['filesize'];
584
  } else {
585
  // Short by more than one byte, throw warning
586
- $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
587
  $info['avdataend'] = $info['filesize'];
588
  }
589
  break;
@@ -592,7 +600,7 @@ class getid3_riff extends getid3_handler {
592
  if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
593
  if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
594
  $info['avdataend']--;
595
- $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
596
  }
597
  }
598
  if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
@@ -611,6 +619,8 @@ class getid3_riff extends getid3_handler {
611
  $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
612
  $thisfile_video['dataformat'] = 'avi';
613
 
 
 
614
  if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
615
  $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
616
  if (isset($thisfile_riff['AVIX'])) {
@@ -619,7 +629,7 @@ class getid3_riff extends getid3_handler {
619
  $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
620
  }
621
  if ($info['avdataend'] > $info['filesize']) {
622
- $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)';
623
  $info['avdataend'] = $info['filesize'];
624
  }
625
  }
@@ -660,7 +670,7 @@ class getid3_riff extends getid3_handler {
660
 
661
  $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
662
  if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
663
- $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
664
  return false;
665
  }
666
 
@@ -693,12 +703,13 @@ class getid3_riff extends getid3_handler {
693
  'capturedfile' => 0x00010000,
694
  'copyrighted' => 0x00020010,
695
  );
696
- foreach ($flags as $flag => $value) {
697
  $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
698
  }
699
 
700
  // shortcut
701
  $thisfile_riff_video[$streamindex] = array();
 
702
  $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
703
 
704
  if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
@@ -858,14 +869,14 @@ class getid3_riff extends getid3_handler {
858
  break;
859
 
860
  default:
861
- $info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';
862
  break;
863
 
864
  }
865
  }
866
  }
867
 
868
- if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
869
 
870
  $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
871
  if (self::fourccLookup($thisfile_video['fourcc'])) {
@@ -912,7 +923,7 @@ class getid3_riff extends getid3_handler {
912
  // http://en.wikipedia.org/wiki/CD-DA
913
  case 'CDDA':
914
  $info['fileformat'] = 'cda';
915
- unset($info['mime_type']);
916
 
917
  $thisfile_audio_dataformat = 'cda';
918
 
@@ -945,7 +956,7 @@ class getid3_riff extends getid3_handler {
945
  }
946
  break;
947
 
948
- // http://en.wikipedia.org/wiki/AIFF
949
  case 'AIFF':
950
  case 'AIFC':
951
  $info['fileformat'] = 'aiff';
@@ -963,7 +974,7 @@ class getid3_riff extends getid3_handler {
963
  // structures rounded to 2-byte boundary, but dumb encoders
964
  // forget to pad end of file to make this actually work
965
  } else {
966
- $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
967
  }
968
  $info['avdataend'] = $info['filesize'];
969
  }
@@ -1020,7 +1031,7 @@ class getid3_riff extends getid3_handler {
1020
  }
1021
  $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
1022
  if ($thisfile_audio['sample_rate'] == 0) {
1023
- $info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
1024
  return false;
1025
  }
1026
  $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
@@ -1055,7 +1066,7 @@ class getid3_riff extends getid3_handler {
1055
  if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
1056
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1057
  $getid3_temp = new getID3();
1058
- $getid3_temp->openfile($this->getid3->filename);
1059
  $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1060
  $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
1061
  if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
@@ -1075,12 +1086,13 @@ class getid3_riff extends getid3_handler {
1075
  $thisfile_audio_dataformat = '8svx';
1076
  $thisfile_audio['bits_per_sample'] = 8;
1077
  $thisfile_audio['channels'] = 1; // overridden below, if need be
 
1078
 
1079
  if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
1080
  $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
1081
  $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
1082
  if ($info['avdataend'] > $info['filesize']) {
1083
- $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
1084
  }
1085
  }
1086
 
@@ -1112,7 +1124,7 @@ class getid3_riff extends getid3_handler {
1112
  break;
1113
 
1114
  default:
1115
- $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';
1116
  break;
1117
  }
1118
  }
@@ -1130,7 +1142,7 @@ class getid3_riff extends getid3_handler {
1130
  break;
1131
 
1132
  default:
1133
- $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';
1134
  break;
1135
  }
1136
 
@@ -1157,7 +1169,7 @@ class getid3_riff extends getid3_handler {
1157
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
1158
 
1159
  $getid3_temp = new getID3();
1160
- $getid3_temp->openfile($this->getid3->filename);
1161
  $getid3_mpeg = new getid3_mpeg($getid3_temp);
1162
  $getid3_mpeg->Analyze();
1163
  if (empty($getid3_temp->info['error'])) {
@@ -1170,9 +1182,59 @@ class getid3_riff extends getid3_handler {
1170
  }
1171
  break;
1172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1173
 
1174
  default:
1175
- $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
1176
  //unset($info['fileformat']);
1177
  }
1178
 
@@ -1185,7 +1247,7 @@ class getid3_riff extends getid3_handler {
1185
  foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
1186
  if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
1187
  $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
1188
- $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"';
1189
  }
1190
  }
1191
 
@@ -1193,7 +1255,7 @@ class getid3_riff extends getid3_handler {
1193
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1194
 
1195
  $getid3_temp = new getID3();
1196
- $getid3_temp->openfile($this->getid3->filename);
1197
  $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1198
  $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
1199
  if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
@@ -1320,6 +1382,15 @@ class getid3_riff extends getid3_handler {
1320
  return true;
1321
  }
1322
 
 
 
 
 
 
 
 
 
 
1323
  public function ParseRIFFAMV($startoffset, $maxoffset) {
1324
  // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
1325
 
@@ -1428,7 +1499,13 @@ class getid3_riff extends getid3_handler {
1428
  return $RIFFchunk;
1429
  }
1430
 
1431
-
 
 
 
 
 
 
1432
  public function ParseRIFF($startoffset, $maxoffset) {
1433
  $info = &$this->getid3->info;
1434
 
@@ -1477,7 +1554,7 @@ class getid3_riff extends getid3_handler {
1477
  // MP3
1478
  if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
1479
  $getid3_temp = new getID3();
1480
- $getid3_temp->openfile($this->getid3->filename);
1481
  $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1482
  $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
1483
  $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
@@ -1499,7 +1576,7 @@ class getid3_riff extends getid3_handler {
1499
 
1500
  // AC3
1501
  $getid3_temp = new getID3();
1502
- $getid3_temp->openfile($this->getid3->filename);
1503
  $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1504
  $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
1505
  $getid3_ac3 = new getid3_ac3($getid3_temp);
@@ -1509,7 +1586,7 @@ class getid3_riff extends getid3_handler {
1509
  $info['ac3'] = $getid3_temp->info['ac3'];
1510
  if (!empty($getid3_temp->info['warning'])) {
1511
  foreach ($getid3_temp->info['warning'] as $key => $value) {
1512
- $info['warning'][] = $value;
1513
  }
1514
  }
1515
  }
@@ -1560,7 +1637,7 @@ class getid3_riff extends getid3_handler {
1560
  // Probably is MP3 data
1561
  if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
1562
  $getid3_temp = new getID3();
1563
- $getid3_temp->openfile($this->getid3->filename);
1564
  $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1565
  $getid3_temp->info['avdataend'] = $info['avdataend'];
1566
  $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
@@ -1577,7 +1654,7 @@ class getid3_riff extends getid3_handler {
1577
  // This is probably AC-3 data
1578
  $getid3_temp = new getID3();
1579
  if ($isRegularAC3) {
1580
- $getid3_temp->openfile($this->getid3->filename);
1581
  $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1582
  $getid3_temp->info['avdataend'] = $info['avdataend'];
1583
  }
@@ -1611,7 +1688,7 @@ class getid3_riff extends getid3_handler {
1611
 
1612
  // This is probably DTS data
1613
  $getid3_temp = new getID3();
1614
- $getid3_temp->openfile($this->getid3->filename);
1615
  $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1616
  $getid3_dts = new getid3_dts($getid3_temp);
1617
  $getid3_dts->Analyze();
@@ -1680,7 +1757,7 @@ class getid3_riff extends getid3_handler {
1680
  // break;
1681
 
1682
  default:
1683
- if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
1684
  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1685
  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
1686
  unset($RIFFchunk[$chunkname][$thisindex]['offset']);
@@ -1715,6 +1792,11 @@ class getid3_riff extends getid3_handler {
1715
  return $RIFFchunk;
1716
  }
1717
 
 
 
 
 
 
1718
  public function ParseRIFFdata(&$RIFFdata) {
1719
  $info = &$this->getid3->info;
1720
  if ($RIFFdata) {
@@ -1752,6 +1834,12 @@ class getid3_riff extends getid3_handler {
1752
  return false;
1753
  }
1754
 
 
 
 
 
 
 
1755
  public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
1756
  $RIFFinfoKeyLookup = array(
1757
  'IARL'=>'archivallocation',
@@ -1811,8 +1899,14 @@ class getid3_riff extends getid3_handler {
1811
  return true;
1812
  }
1813
 
 
 
 
 
 
1814
  public static function parseWAVEFORMATex($WaveFormatExData) {
1815
  // shortcut
 
1816
  $WaveFormatEx['raw'] = array();
1817
  $WaveFormatEx_raw = &$WaveFormatEx['raw'];
1818
 
@@ -1836,6 +1930,11 @@ class getid3_riff extends getid3_handler {
1836
  return $WaveFormatEx;
1837
  }
1838
 
 
 
 
 
 
1839
  public function parseWavPackHeader($WavPackChunkData) {
1840
  // typedef struct {
1841
  // char ckID [4];
@@ -1897,6 +1996,12 @@ class getid3_riff extends getid3_handler {
1897
  return true;
1898
  }
1899
 
 
 
 
 
 
 
1900
  public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
1901
 
1902
  $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
@@ -1916,6 +2021,12 @@ class getid3_riff extends getid3_handler {
1916
  return $parsed;
1917
  }
1918
 
 
 
 
 
 
 
1919
  public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
1920
  // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
1921
  // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
@@ -1962,6 +2073,7 @@ class getid3_riff extends getid3_handler {
1962
  5 => 'NC-17',
1963
  );
1964
 
 
1965
  $parsed['title'] = trim(substr($DIVXTAG, 0, 32));
1966
  $parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
1967
  $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
@@ -1977,8 +2089,8 @@ class getid3_riff extends getid3_handler {
1977
  if (!$raw) {
1978
  unset($parsed['genre_id'], $parsed['rating_id']);
1979
  foreach ($parsed as $key => $value) {
1980
- if (!$value === '') {
1981
- unset($parsed['key']);
1982
  }
1983
  }
1984
  }
@@ -1990,6 +2102,11 @@ class getid3_riff extends getid3_handler {
1990
  return $parsed;
1991
  }
1992
 
 
 
 
 
 
1993
  public static function waveSNDMtagLookup($tagshortname) {
1994
  $begin = __LINE__;
1995
 
@@ -2013,6 +2130,11 @@ class getid3_riff extends getid3_handler {
2013
  return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
2014
  }
2015
 
 
 
 
 
 
2016
  public static function wFormatTagLookup($wFormatTag) {
2017
 
2018
  $begin = __LINE__;
@@ -2182,6 +2304,11 @@ class getid3_riff extends getid3_handler {
2182
  return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
2183
  }
2184
 
 
 
 
 
 
2185
  public static function fourccLookup($fourcc) {
2186
 
2187
  $begin = __LINE__;
@@ -2576,6 +2703,12 @@ class getid3_riff extends getid3_handler {
2576
  return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
2577
  }
2578
 
 
 
 
 
 
 
2579
  private function EitherEndian2Int($byteword, $signed=false) {
2580
  if ($this->container == 'riff') {
2581
  return getid3_lib::LittleEndian2Int($byteword, $signed);
@@ -2583,4 +2716,4 @@ class getid3_riff extends getid3_handler {
2583
  return getid3_lib::BigEndian2Int($byteword, false, $signed);
2584
  }
2585
 
2586
- }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.riff.php //
27
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
28
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
29
 
30
+ class getid3_riff extends getid3_handler
31
+ {
32
  protected $container = 'riff'; // default
33
 
34
+ /**
35
+ * @return bool
36
+ *
37
+ * @throws getid3_exception
38
+ */
39
  public function Analyze() {
40
  $info = &$this->getid3->info;
41
 
51
  $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
52
  $thisfile_riff_audio = &$thisfile_riff['audio'];
53
  $thisfile_riff_video = &$thisfile_riff['video'];
54
+ $thisfile_riff_WAVE = array();
55
 
56
  $Original['avdataoffset'] = $info['avdataoffset'];
57
  $Original['avdataend'] = $info['avdataend'];
196
  $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
197
  $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
198
  if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
199
+ $this->error('Corrupt RIFF file: bitrate_audio == zero');
200
  return false;
201
  }
202
  $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
205
 
206
  $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
207
  if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
208
+ $this->warning('Audio codec = '.$thisfile_audio['codec']);
209
  }
210
  $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
211
 
308
  list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
309
  $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
310
  } else {
311
+ $this->warning('RIFF.WAVE.BEXT.origin_time is invalid');
312
  }
313
  } else {
314
+ $this->warning('RIFF.WAVE.BEXT.origin_date is invalid');
315
  }
316
  $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
317
  $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
363
  }
364
  $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
365
  $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
366
+ $thisfile_riff['comments']['tag_text'][] = substr($thisfile_riff_WAVE_cart_0['data'], 1772);
367
 
368
  $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
369
  $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
392
  $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
393
 
394
  if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
395
+ $this->warning('RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
396
  break;
397
  } elseif ($SNDM_thisTagSize <= 0) {
398
+ $this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
399
  break;
400
  }
401
  $SNDM_startoffset += $SNDM_thisTagSize;
404
  if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
405
  $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
406
  } else {
407
+ $this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
408
  }
409
  }
410
 
412
  'tracktitle'=>'title',
413
  'category' =>'genre',
414
  'cdtitle' =>'album',
 
415
  );
416
  foreach ($tagmapping as $fromkey => $tokey) {
417
  if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
434
  }
435
  if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
436
  $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
437
+ $timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105
438
+ $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
439
  $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
440
  $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
441
  $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
442
  $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
443
  $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
444
  $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
445
+ unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f);
446
  }
447
  unset($parsedXML);
448
  }
578
  // byte, in which case - skip warning
579
  } else {
580
  // Short by more than one byte, throw warning
581
+ $this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)');
582
  $info['avdataend'] = $info['filesize'];
583
  }
584
  break;
587
  if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
588
  // output file appears to be incorrectly *not* padded to nearest WORD boundary
589
  // Output less severe warning
590
+ $this->warning('File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)');
591
  $info['avdataend'] = $info['filesize'];
592
  } else {
593
  // Short by more than one byte, throw warning
594
+ $this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)');
595
  $info['avdataend'] = $info['filesize'];
596
  }
597
  break;
600
  if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
601
  if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
602
  $info['avdataend']--;
603
+ $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
604
  }
605
  }
606
  if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
619
  $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
620
  $thisfile_video['dataformat'] = 'avi';
621
 
622
+ $thisfile_riff_video_current = array();
623
+
624
  if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
625
  $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
626
  if (isset($thisfile_riff['AVIX'])) {
629
  $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
630
  }
631
  if ($info['avdataend'] > $info['filesize']) {
632
+ $this->warning('Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)');
633
  $info['avdataend'] = $info['filesize'];
634
  }
635
  }
670
 
671
  $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
672
  if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
673
+ $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero');
674
  return false;
675
  }
676
 
703
  'capturedfile' => 0x00010000,
704
  'copyrighted' => 0x00020010,
705
  );
706
+ foreach ($flags as $flag => $value) {
707
  $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
708
  }
709
 
710
  // shortcut
711
  $thisfile_riff_video[$streamindex] = array();
712
+ /** @var array $thisfile_riff_video_current */
713
  $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
714
 
715
  if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
869
  break;
870
 
871
  default:
872
+ $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"');
873
  break;
874
 
875
  }
876
  }
877
  }
878
 
879
+ if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
880
 
881
  $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
882
  if (self::fourccLookup($thisfile_video['fourcc'])) {
923
  // http://en.wikipedia.org/wiki/CD-DA
924
  case 'CDDA':
925
  $info['fileformat'] = 'cda';
926
+ unset($info['mime_type']);
927
 
928
  $thisfile_audio_dataformat = 'cda';
929
 
956
  }
957
  break;
958
 
959
+ // http://en.wikipedia.org/wiki/AIFF
960
  case 'AIFF':
961
  case 'AIFC':
962
  $info['fileformat'] = 'aiff';
974
  // structures rounded to 2-byte boundary, but dumb encoders
975
  // forget to pad end of file to make this actually work
976
  } else {
977
+ $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
978
  }
979
  $info['avdataend'] = $info['filesize'];
980
  }
1031
  }
1032
  $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
1033
  if ($thisfile_audio['sample_rate'] == 0) {
1034
+ $this->error('Corrupted AIFF file: sample_rate == zero');
1035
  return false;
1036
  }
1037
  $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
1066
  if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
1067
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1068
  $getid3_temp = new getID3();
1069
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1070
  $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1071
  $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
1072
  if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1086
  $thisfile_audio_dataformat = '8svx';
1087
  $thisfile_audio['bits_per_sample'] = 8;
1088
  $thisfile_audio['channels'] = 1; // overridden below, if need be
1089
+ $ActualBitsPerSample = 0;
1090
 
1091
  if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
1092
  $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
1093
  $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
1094
  if ($info['avdataend'] > $info['filesize']) {
1095
+ $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
1096
  }
1097
  }
1098
 
1124
  break;
1125
 
1126
  default:
1127
+ $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"');
1128
  break;
1129
  }
1130
  }
1142
  break;
1143
 
1144
  default:
1145
+ $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
1146
  break;
1147
  }
1148
 
1169
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
1170
 
1171
  $getid3_temp = new getID3();
1172
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1173
  $getid3_mpeg = new getid3_mpeg($getid3_temp);
1174
  $getid3_mpeg->Analyze();
1175
  if (empty($getid3_temp->info['error'])) {
1182
  }
1183
  break;
1184
 
1185
+ case 'WEBP':
1186
+ // https://developers.google.com/speed/webp/docs/riff_container
1187
+ // https://tools.ietf.org/html/rfc6386
1188
+ // https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
1189
+ $info['fileformat'] = 'webp';
1190
+ $info['mime_type'] = 'image/webp';
1191
+
1192
+ if (!empty($thisfile_riff['WEBP']['VP8 '][0]['size'])) {
1193
+ $old_offset = $this->ftell();
1194
+ $this->fseek($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8); // 4 bytes "VP8 " + 4 bytes chunk size
1195
+ $WEBP_VP8_header = $this->fread(10);
1196
+ $this->fseek($old_offset);
1197
+ if (substr($WEBP_VP8_header, 3, 3) == "\x9D\x01\x2A") {
1198
+ $thisfile_riff['WEBP']['VP8 '][0]['keyframe'] = !(getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x800000);
1199
+ $thisfile_riff['WEBP']['VP8 '][0]['version'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x700000) >> 20;
1200
+ $thisfile_riff['WEBP']['VP8 '][0]['show_frame'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x080000);
1201
+ $thisfile_riff['WEBP']['VP8 '][0]['data_bytes'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x07FFFF) >> 0;
1202
+
1203
+ $thisfile_riff['WEBP']['VP8 '][0]['scale_x'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0xC000) >> 14;
1204
+ $thisfile_riff['WEBP']['VP8 '][0]['width'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0x3FFF);
1205
+ $thisfile_riff['WEBP']['VP8 '][0]['scale_y'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0xC000) >> 14;
1206
+ $thisfile_riff['WEBP']['VP8 '][0]['height'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0x3FFF);
1207
+
1208
+ $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width'];
1209
+ $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height'];
1210
+ } else {
1211
+ $this->error('Expecting 9D 01 2A at offset '.($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8 + 3).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8_header, 3, 3)).'"');
1212
+ }
1213
+
1214
+ }
1215
+ if (!empty($thisfile_riff['WEBP']['VP8L'][0]['size'])) {
1216
+ $old_offset = $this->ftell();
1217
+ $this->fseek($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8); // 4 bytes "VP8L" + 4 bytes chunk size
1218
+ $WEBP_VP8L_header = $this->fread(10);
1219
+ $this->fseek($old_offset);
1220
+ if (substr($WEBP_VP8L_header, 0, 1) == "\x2F") {
1221
+ $width_height_flags = getid3_lib::LittleEndian2Bin(substr($WEBP_VP8L_header, 1, 4));
1222
+ $thisfile_riff['WEBP']['VP8L'][0]['width'] = bindec(substr($width_height_flags, 18, 14)) + 1;
1223
+ $thisfile_riff['WEBP']['VP8L'][0]['height'] = bindec(substr($width_height_flags, 4, 14)) + 1;
1224
+ $thisfile_riff['WEBP']['VP8L'][0]['alpha_is_used'] = (bool) bindec(substr($width_height_flags, 3, 1));
1225
+ $thisfile_riff['WEBP']['VP8L'][0]['version'] = bindec(substr($width_height_flags, 0, 3));
1226
+
1227
+ $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width'];
1228
+ $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height'];
1229
+ } else {
1230
+ $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"');
1231
+ }
1232
+
1233
+ }
1234
+ break;
1235
 
1236
  default:
1237
+ $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead');
1238
  //unset($info['fileformat']);
1239
  }
1240
 
1247
  foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
1248
  if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
1249
  $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
1250
+ $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"');
1251
  }
1252
  }
1253
 
1255
  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1256
 
1257
  $getid3_temp = new getID3();
1258
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1259
  $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1260
  $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
1261
  if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1382
  return true;
1383
  }
1384
 
1385
+ /**
1386
+ * @param int $startoffset
1387
+ * @param int $maxoffset
1388
+ *
1389
+ * @return array|false
1390
+ *
1391
+ * @throws Exception
1392
+ * @throws getid3_exception
1393
+ */
1394
  public function ParseRIFFAMV($startoffset, $maxoffset) {
1395
  // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
1396
 
1499
  return $RIFFchunk;
1500
  }
1501
 
1502
+ /**
1503
+ * @param int $startoffset
1504
+ * @param int $maxoffset
1505
+ *
1506
+ * @return array|false
1507
+ * @throws getid3_exception
1508
+ */
1509
  public function ParseRIFF($startoffset, $maxoffset) {
1510
  $info = &$this->getid3->info;
1511
 
1554
  // MP3
1555
  if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
1556
  $getid3_temp = new getID3();
1557
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1558
  $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1559
  $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
1560
  $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
1576
 
1577
  // AC3
1578
  $getid3_temp = new getID3();
1579
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1580
  $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1581
  $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
1582
  $getid3_ac3 = new getid3_ac3($getid3_temp);
1586
  $info['ac3'] = $getid3_temp->info['ac3'];
1587
  if (!empty($getid3_temp->info['warning'])) {
1588
  foreach ($getid3_temp->info['warning'] as $key => $value) {
1589
+ $this->warning($value);
1590
  }
1591
  }
1592
  }
1637
  // Probably is MP3 data
1638
  if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
1639
  $getid3_temp = new getID3();
1640
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1641
  $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1642
  $getid3_temp->info['avdataend'] = $info['avdataend'];
1643
  $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
1654
  // This is probably AC-3 data
1655
  $getid3_temp = new getID3();
1656
  if ($isRegularAC3) {
1657
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1658
  $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1659
  $getid3_temp->info['avdataend'] = $info['avdataend'];
1660
  }
1688
 
1689
  // This is probably DTS data
1690
  $getid3_temp = new getID3();
1691
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
1692
  $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1693
  $getid3_dts = new getid3_dts($getid3_temp);
1694
  $getid3_dts->Analyze();
1757
  // break;
1758
 
1759
  default:
1760
+ if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
1761
  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1762
  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
1763
  unset($RIFFchunk[$chunkname][$thisindex]['offset']);
1792
  return $RIFFchunk;
1793
  }
1794
 
1795
+ /**
1796
+ * @param string $RIFFdata
1797
+ *
1798
+ * @return bool
1799
+ */
1800
  public function ParseRIFFdata(&$RIFFdata) {
1801
  $info = &$this->getid3->info;
1802
  if ($RIFFdata) {
1834
  return false;
1835
  }
1836
 
1837
+ /**
1838
+ * @param array $RIFFinfoArray
1839
+ * @param array $CommentsTargetArray
1840
+ *
1841
+ * @return bool
1842
+ */
1843
  public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
1844
  $RIFFinfoKeyLookup = array(
1845
  'IARL'=>'archivallocation',
1899
  return true;
1900
  }
1901
 
1902
+ /**
1903
+ * @param string $WaveFormatExData
1904
+ *
1905
+ * @return array
1906
+ */
1907
  public static function parseWAVEFORMATex($WaveFormatExData) {
1908
  // shortcut
1909
+ $WaveFormatEx = array();
1910
  $WaveFormatEx['raw'] = array();
1911
  $WaveFormatEx_raw = &$WaveFormatEx['raw'];
1912
 
1930
  return $WaveFormatEx;
1931
  }
1932
 
1933
+ /**
1934
+ * @param string $WavPackChunkData
1935
+ *
1936
+ * @return bool
1937
+ */
1938
  public function parseWavPackHeader($WavPackChunkData) {
1939
  // typedef struct {
1940
  // char ckID [4];
1996
  return true;
1997
  }
1998
 
1999
+ /**
2000
+ * @param string $BITMAPINFOHEADER
2001
+ * @param bool $littleEndian
2002
+ *
2003
+ * @return array
2004
+ */
2005
  public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
2006
 
2007
  $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
2021
  return $parsed;
2022
  }
2023
 
2024
+ /**
2025
+ * @param string $DIVXTAG
2026
+ * @param bool $raw
2027
+ *
2028
+ * @return array
2029
+ */
2030
  public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
2031
  // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
2032
  // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
2073
  5 => 'NC-17',
2074
  );
2075
 
2076
+ $parsed = array();
2077
  $parsed['title'] = trim(substr($DIVXTAG, 0, 32));
2078
  $parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
2079
  $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
2089
  if (!$raw) {
2090
  unset($parsed['genre_id'], $parsed['rating_id']);
2091
  foreach ($parsed as $key => $value) {
2092
+ if (empty($value)) {
2093
+ unset($parsed[$key]);
2094
  }
2095
  }
2096
  }
2102
  return $parsed;
2103
  }
2104
 
2105
+ /**
2106
+ * @param string $tagshortname
2107
+ *
2108
+ * @return string
2109
+ */
2110
  public static function waveSNDMtagLookup($tagshortname) {
2111
  $begin = __LINE__;
2112
 
2130
  return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
2131
  }
2132
 
2133
+ /**
2134
+ * @param int $wFormatTag
2135
+ *
2136
+ * @return string
2137
+ */
2138
  public static function wFormatTagLookup($wFormatTag) {
2139
 
2140
  $begin = __LINE__;
2304
  return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
2305
  }
2306
 
2307
+ /**
2308
+ * @param string $fourcc
2309
+ *
2310
+ * @return string
2311
+ */
2312
  public static function fourccLookup($fourcc) {
2313
 
2314
  $begin = __LINE__;
2703
  return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
2704
  }
2705
 
2706
+ /**
2707
+ * @param string $byteword
2708
+ * @param bool $signed
2709
+ *
2710
+ * @return int|float|false
2711
+ */
2712
  private function EitherEndian2Int($byteword, $signed=false) {
2713
  if ($this->container == 'riff') {
2714
  return getid3_lib::LittleEndian2Int($byteword, $signed);
2716
  return getid3_lib::BigEndian2Int($byteword, false, $signed);
2717
  }
2718
 
2719
+ }
lib/getid3/module.audio-video.swf.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.swf.php //
@@ -19,6 +19,9 @@ class getid3_swf extends getid3_handler
19
  {
20
  public $ReturnAllTagData = false;
21
 
 
 
 
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
@@ -42,7 +45,7 @@ class getid3_swf extends getid3_handler
42
  break;
43
 
44
  default:
45
- $info['error'][] = 'Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"';
46
  unset($info['swf']);
47
  unset($info['fileformat']);
48
  return false;
@@ -57,7 +60,7 @@ class getid3_swf extends getid3_handler
57
  if ($decompressed = @gzuncompress($SWFfileData)) {
58
  $SWFfileData = $SWFHead.$decompressed;
59
  } else {
60
- $info['error'][] = 'Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)';
61
  return false;
62
  }
63
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.swf.php //
19
  {
20
  public $ReturnAllTagData = false;
21
 
22
+ /**
23
+ * @return bool
24
+ */
25
  public function Analyze() {
26
  $info = &$this->getid3->info;
27
 
45
  break;
46
 
47
  default:
48
+ $this->error('Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"');
49
  unset($info['swf']);
50
  unset($info['fileformat']);
51
  return false;
60
  if ($decompressed = @gzuncompress($SWFfileData)) {
61
  $SWFfileData = $SWFHead.$decompressed;
62
  } else {
63
+ $this->error('Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)');
64
  return false;
65
  }
66
  }
lib/getid3/module.audio-video.ts.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.ts.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_ts extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -25,7 +27,7 @@ class getid3_ts extends getid3_handler
25
  $TSheader = $this->fread(19);
26
  $magic = "\x47";
27
  if (substr($TSheader, 0, 1) != $magic) {
28
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.';
29
  return false;
30
  }
31
  $info['fileformat'] = 'ts';
@@ -66,12 +68,16 @@ class getid3_ts extends getid3_handler
66
  }
67
  }
68
 
69
- $info['error'][] = 'MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
70
- return false;
71
 
72
  }
73
 
74
-
 
 
 
 
75
  public function TSscramblingControlLookup($raw) {
76
  $TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key');
77
  return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid');
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio-video.ts.php //
17
 
18
  class getid3_ts extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
27
  $TSheader = $this->fread(19);
28
  $magic = "\x47";
29
  if (substr($TSheader, 0, 1) != $magic) {
30
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.');
31
  return false;
32
  }
33
  $info['fileformat'] = 'ts';
68
  }
69
  }
70
 
71
+ $this->error('MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
72
+ return false;
73
 
74
  }
75
 
76
+ /**
77
+ * @param int $raw
78
+ *
79
+ * @return string
80
+ */
81
  public function TSscramblingControlLookup($raw) {
82
  $TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key');
83
  return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid');
lib/getid3/module.audio.aa.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.aa.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_aa extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -26,7 +28,7 @@ class getid3_aa extends getid3_handler
26
 
27
  $magic = "\x57\x90\x75\x36";
28
  if (substr($AAheader, 4, 4) != $magic) {
29
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"';
30
  return false;
31
  }
32
 
@@ -36,14 +38,14 @@ class getid3_aa extends getid3_handler
36
 
37
  $info['fileformat'] = 'aa';
38
  $info['audio']['dataformat'] = 'aa';
39
- $info['error'][] = 'Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
40
- return false;
41
  $info['audio']['bitrate_mode'] = 'cbr'; // is it?
42
  $thisfile_aa['encoding'] = 'ISO-8859-1';
43
 
44
- $thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AUheader, 0, 4));
45
  if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) {
46
- $info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"';
47
  }
48
 
49
  $info['audio']['bits_per_sample'] = 16; // is it?
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.aa.php //
17
 
18
  class getid3_aa extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
28
 
29
  $magic = "\x57\x90\x75\x36";
30
  if (substr($AAheader, 4, 4) != $magic) {
31
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"');
32
  return false;
33
  }
34
 
38
 
39
  $info['fileformat'] = 'aa';
40
  $info['audio']['dataformat'] = 'aa';
41
+ $this->error('Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
42
+ return false;
43
  $info['audio']['bitrate_mode'] = 'cbr'; // is it?
44
  $thisfile_aa['encoding'] = 'ISO-8859-1';
45
 
46
+ $thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AAheader, 0, 4));
47
  if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) {
48
+ $this->warning('Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
49
  }
50
 
51
  $info['audio']['bits_per_sample'] = 16; // is it?
lib/getid3/module.audio.aac.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.aac.php //
@@ -17,6 +17,9 @@
17
 
18
  class getid3_aac extends getid3_handler
19
  {
 
 
 
20
  public function Analyze() {
21
  $info = &$this->getid3->info;
22
  $this->fseek($info['avdataoffset']);
@@ -28,8 +31,9 @@ class getid3_aac extends getid3_handler
28
  return true;
29
  }
30
 
31
-
32
-
 
33
  public function getAACADIFheaderFilepointer() {
34
  $info = &$this->getid3->info;
35
  $info['fileformat'] = 'aac';
@@ -69,17 +73,17 @@ class getid3_aac extends getid3_handler
69
  $bitoffset += 32;
70
  $info['aac']['header']['mpeg_version'] = 4;
71
 
72
- $info['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
73
  $bitoffset += 1;
74
  if ($info['aac']['header']['copyright']) {
75
  $info['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
76
  $bitoffset += 72;
77
  }
78
- $info['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
79
  $bitoffset += 1;
80
- $info['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
81
  $bitoffset += 1;
82
- $info['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
83
  $bitoffset += 1;
84
  if ($info['aac']['header']['is_vbr']) {
85
  $info['audio']['bitrate_mode'] = 'vbr';
@@ -92,7 +96,7 @@ class getid3_aac extends getid3_handler
92
  $info['audio']['bitrate'] = $info['aac']['header']['bitrate'];
93
  }
94
  if ($info['audio']['bitrate'] == 0) {
95
- $info['error'][] = 'Corrupt AAC file: bitrate_audio == zero';
96
  return false;
97
  }
98
  $info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
@@ -250,14 +254,19 @@ class getid3_aac extends getid3_handler
250
 
251
  unset($info['fileformat']);
252
  unset($info['aac']);
253
- $info['error'][] = 'AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)';
254
  return false;
255
 
256
  }
257
 
258
  }
259
 
260
-
 
 
 
 
 
261
  public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
262
  $info = &$this->getid3->info;
263
 
@@ -311,7 +320,7 @@ class getid3_aac extends getid3_handler
311
  // or MaxFramesToScan frames have been scanned
312
 
313
  if (!getid3_lib::intValueSupported($byteoffset)) {
314
- $info['warning'][] = 'Unable to parse AAC file beyond '.$this->ftell().' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
315
  return false;
316
  }
317
  $this->fseek($byteoffset);
@@ -320,7 +329,7 @@ class getid3_aac extends getid3_handler
320
  $substring = $this->fread(9); // header is 7 bytes (or 9 if CRC is present)
321
  $substringlength = strlen($substring);
322
  if ($substringlength != 9) {
323
- $info['error'][] = 'Failed to read 7 bytes at offset '.($this->ftell() - $substringlength).' (only read '.$substringlength.' bytes)';
324
  return false;
325
  }
326
  // this would be easier with 64-bit math, but split it up to allow for 32-bit:
@@ -330,7 +339,7 @@ class getid3_aac extends getid3_handler
330
 
331
  $info['aac']['header']['raw']['syncword'] = ($header1 & 0xFFF0) >> 4;
332
  if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) {
333
- $info['error'][] = 'Synch pattern (0x0FFF) not found at offset '.($this->ftell() - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)';
334
  //if ($info['fileformat'] == 'aac') {
335
  // return true;
336
  //}
@@ -372,10 +381,10 @@ class getid3_aac extends getid3_handler
372
  }
373
 
374
  if ($info['aac']['header']['raw']['mpeg_layer'] != 0) {
375
- $info['warning'][] = 'Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead';
376
  }
377
  if ($info['aac']['header']['sample_frequency'] == 0) {
378
- $info['error'][] = 'Corrupt AAC file: sample_frequency == zero';
379
  return false;
380
  }
381
 
@@ -428,7 +437,7 @@ class getid3_aac extends getid3_handler
428
  $info['aac']['frames'] = $framenumber;
429
  $info['playtime_seconds'] = ($info['avdataend'] / $byteoffset) * (($framenumber * 1024) / $info['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
430
  if ($info['playtime_seconds'] == 0) {
431
- $info['error'][] = 'Corrupt AAC file: playtime_seconds == zero';
432
  return false;
433
  }
434
  $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
@@ -443,6 +452,11 @@ class getid3_aac extends getid3_handler
443
  // should never get here.
444
  }
445
 
 
 
 
 
 
446
  public static function AACsampleRateLookup($samplerateid) {
447
  static $AACsampleRateLookup = array();
448
  if (empty($AACsampleRateLookup)) {
@@ -466,6 +480,12 @@ class getid3_aac extends getid3_handler
466
  return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
467
  }
468
 
 
 
 
 
 
 
469
  public static function AACprofileLookup($profileid, $mpegversion) {
470
  static $AACprofileLookup = array();
471
  if (empty($AACprofileLookup)) {
@@ -481,6 +501,11 @@ class getid3_aac extends getid3_handler
481
  return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
482
  }
483
 
 
 
 
 
 
484
  public static function AACchannelCountCalculate($program_configs) {
485
  $channels = 0;
486
  for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.aac.php //
17
 
18
  class getid3_aac extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
  $this->fseek($info['avdataoffset']);
31
  return true;
32
  }
33
 
34
+ /**
35
+ * @return bool
36
+ */
37
  public function getAACADIFheaderFilepointer() {
38
  $info = &$this->getid3->info;
39
  $info['fileformat'] = 'aac';
73
  $bitoffset += 32;
74
  $info['aac']['header']['mpeg_version'] = 4;
75
 
76
+ $info['aac']['header']['copyright'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
77
  $bitoffset += 1;
78
  if ($info['aac']['header']['copyright']) {
79
  $info['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
80
  $bitoffset += 72;
81
  }
82
+ $info['aac']['header']['original_copy'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
83
  $bitoffset += 1;
84
+ $info['aac']['header']['home'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
85
  $bitoffset += 1;
86
+ $info['aac']['header']['is_vbr'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
87
  $bitoffset += 1;
88
  if ($info['aac']['header']['is_vbr']) {
89
  $info['audio']['bitrate_mode'] = 'vbr';
96
  $info['audio']['bitrate'] = $info['aac']['header']['bitrate'];
97
  }
98
  if ($info['audio']['bitrate'] == 0) {
99
+ $this->error('Corrupt AAC file: bitrate_audio == zero');
100
  return false;
101
  }
102
  $info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
254
 
255
  unset($info['fileformat']);
256
  unset($info['aac']);
257
+ $this->error('AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)');
258
  return false;
259
 
260
  }
261
 
262
  }
263
 
264
+ /**
265
+ * @param int $MaxFramesToScan
266
+ * @param bool $ReturnExtendedInfo
267
+ *
268
+ * @return bool
269
+ */
270
  public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
271
  $info = &$this->getid3->info;
272
 
320
  // or MaxFramesToScan frames have been scanned
321
 
322
  if (!getid3_lib::intValueSupported($byteoffset)) {
323
+ $this->warning('Unable to parse AAC file beyond '.$this->ftell().' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
324
  return false;
325
  }
326
  $this->fseek($byteoffset);
329
  $substring = $this->fread(9); // header is 7 bytes (or 9 if CRC is present)
330
  $substringlength = strlen($substring);
331
  if ($substringlength != 9) {
332
+ $this->error('Failed to read 7 bytes at offset '.($this->ftell() - $substringlength).' (only read '.$substringlength.' bytes)');
333
  return false;
334
  }
335
  // this would be easier with 64-bit math, but split it up to allow for 32-bit:
339
 
340
  $info['aac']['header']['raw']['syncword'] = ($header1 & 0xFFF0) >> 4;
341
  if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) {
342
+ $this->error('Synch pattern (0x0FFF) not found at offset '.($this->ftell() - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)');
343
  //if ($info['fileformat'] == 'aac') {
344
  // return true;
345
  //}
381
  }
382
 
383
  if ($info['aac']['header']['raw']['mpeg_layer'] != 0) {
384
+ $this->warning('Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead');
385
  }
386
  if ($info['aac']['header']['sample_frequency'] == 0) {
387
+ $this->error('Corrupt AAC file: sample_frequency == zero');
388
  return false;
389
  }
390
 
437
  $info['aac']['frames'] = $framenumber;
438
  $info['playtime_seconds'] = ($info['avdataend'] / $byteoffset) * (($framenumber * 1024) / $info['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
439
  if ($info['playtime_seconds'] == 0) {
440
+ $this->error('Corrupt AAC file: playtime_seconds == zero');
441
  return false;
442
  }
443
  $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
452
  // should never get here.
453
  }
454
 
455
+ /**
456
+ * @param int $samplerateid
457
+ *
458
+ * @return int|string
459
+ */
460
  public static function AACsampleRateLookup($samplerateid) {
461
  static $AACsampleRateLookup = array();
462
  if (empty($AACsampleRateLookup)) {
480
  return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
481
  }
482
 
483
+ /**
484
+ * @param int $profileid
485
+ * @param int $mpegversion
486
+ *
487
+ * @return string
488
+ */
489
  public static function AACprofileLookup($profileid, $mpegversion) {
490
  static $AACprofileLookup = array();
491
  if (empty($AACprofileLookup)) {
501
  return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
502
  }
503
 
504
+ /**
505
+ * @param array $program_configs
506
+ *
507
+ * @return int
508
+ */
509
  public static function AACchannelCountCalculate($program_configs) {
510
  $channels = 0;
511
  for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
lib/getid3/module.audio.ac3.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.ac3.php //
@@ -17,11 +17,21 @@
17
 
18
  class getid3_ac3 extends getid3_handler
19
  {
20
- private $AC3header = array();
21
- private $BSIoffset = 0;
 
 
22
 
23
- const syncword = "\x0B\x77";
 
 
 
24
 
 
 
 
 
 
25
  public function Analyze() {
26
  $info = &$this->getid3->info;
27
 
@@ -55,185 +65,428 @@ class getid3_ac3 extends getid3_handler
55
  // } /* end of syncinfo */
56
 
57
  $this->fseek($info['avdataoffset']);
58
- $this->AC3header['syncinfo'] = $this->fread(5);
 
 
 
 
59
 
60
- if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) {
61
- $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword;
62
- $offset = 2;
63
- } else {
64
  if (!$this->isDependencyFor('matroska')) {
65
  unset($info['fileformat'], $info['ac3']);
66
- return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"');
67
  }
68
- $offset = 0;
69
- $this->fseek(-2, SEEK_CUR);
70
  }
71
 
72
  $info['audio']['dataformat'] = 'ac3';
73
  $info['audio']['bitrate_mode'] = 'cbr';
74
  $info['audio']['lossless'] = false;
75
 
76
- $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2));
77
- $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1));
78
- $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
79
- $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
80
 
81
- $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
82
- if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
83
- $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
84
- }
 
 
85
 
86
- $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
87
- $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
88
- $info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
89
 
90
- $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15));
91
- $ac3_bsi_offset = 0;
 
 
 
92
 
93
- $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5);
94
- if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
95
- // Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
96
- // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
97
- // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
98
- $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8');
99
- unset($info['ac3']);
100
- return false;
101
- }
102
 
103
- $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
104
- $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
 
 
 
105
 
106
- $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
107
- $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
108
- foreach($ac3_coding_mode as $key => $value) {
109
- $thisfile_ac3[$key] = $value;
110
- }
111
- switch ($thisfile_ac3_raw_bsi['acmod']) {
112
- case 0:
113
- case 1:
114
- $info['audio']['channelmode'] = 'mono';
115
- break;
116
- case 3:
117
- case 4:
118
- $info['audio']['channelmode'] = 'stereo';
119
- break;
120
- default:
121
- $info['audio']['channelmode'] = 'surround';
122
- break;
123
- }
124
- $info['audio']['channels'] = $thisfile_ac3['num_channels'];
125
 
126
- if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
127
- // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
128
- $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
129
- $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
130
- }
131
 
132
- if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
133
- // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
134
- $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
135
- $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
136
- }
137
 
138
- if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
139
- // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
140
- $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
141
- $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
142
- }
143
 
144
- $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
145
- $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
146
- if ($thisfile_ac3_raw_bsi['lfeon']) {
147
- //$info['audio']['channels']++;
148
- $info['audio']['channels'] .= '.1';
149
- }
150
 
151
- $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
 
 
152
 
153
- // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
154
- // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
155
- $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
156
- $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
157
 
158
- $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);
159
- if ($thisfile_ac3_raw_bsi['compre_flag']) {
160
- $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
161
- $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
162
- }
163
 
164
- $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);
165
- if ($thisfile_ac3_raw_bsi['langcode_flag']) {
166
- $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);
167
- }
 
168
 
169
- $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);
170
- if ($thisfile_ac3_raw_bsi['audprodie']) {
171
- $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
172
- $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
173
 
174
- $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
175
- $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
176
- }
 
 
 
 
 
177
 
178
- if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {
179
- // If acmod is 0, then two completely independent program channels (dual mono)
180
- // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
181
- // a number of additional items are present in BSI or audblk to fully describe Ch2.
182
 
183
- // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
184
- // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
185
- $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
186
- $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
187
 
188
- $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);
189
- if ($thisfile_ac3_raw_bsi['compre_flag2']) {
190
- $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
191
- $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
 
 
 
192
  }
193
-
194
- $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);
195
- if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
196
- $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);
 
 
197
  }
198
 
199
- $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);
200
- if ($thisfile_ac3_raw_bsi['audprodie2']) {
201
- $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
202
- $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
203
 
204
- $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
205
- $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
 
 
206
  }
207
 
208
- }
209
 
210
- $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1);
211
 
212
- $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1);
213
 
214
- $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);
215
- if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
216
- $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);
217
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
 
219
- $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);
220
- if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
221
- $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);
222
  }
223
 
224
- $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);
225
- if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
226
- $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
- $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
231
- $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
 
232
  }
233
 
 
 
 
234
  return true;
235
  }
236
 
 
 
 
 
 
237
  private function readHeaderBSI($length) {
238
  $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
239
  $this->BSIoffset += $length;
@@ -241,6 +494,11 @@ class getid3_ac3 extends getid3_handler
241
  return bindec($data);
242
  }
243
 
 
 
 
 
 
244
  public static function sampleRateCodeLookup($fscod) {
245
  static $sampleRateCodeLookup = array(
246
  0 => 48000,
@@ -251,6 +509,27 @@ class getid3_ac3 extends getid3_handler
251
  return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
252
  }
253
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  public static function serviceTypeLookup($bsmod, $acmod) {
255
  static $serviceTypeLookup = array();
256
  if (empty($serviceTypeLookup)) {
@@ -272,6 +551,11 @@ class getid3_ac3 extends getid3_handler
272
  return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
273
  }
274
 
 
 
 
 
 
275
  public static function audioCodingModeLookup($acmod) {
276
  // array(channel configuration, # channels (not incl LFE), channel order)
277
  static $audioCodingModeLookup = array (
@@ -287,6 +571,11 @@ class getid3_ac3 extends getid3_handler
287
  return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
288
  }
289
 
 
 
 
 
 
290
  public static function centerMixLevelLookup($cmixlev) {
291
  static $centerMixLevelLookup;
292
  if (empty($centerMixLevelLookup)) {
@@ -300,6 +589,11 @@ class getid3_ac3 extends getid3_handler
300
  return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
301
  }
302
 
 
 
 
 
 
303
  public static function surroundMixLevelLookup($surmixlev) {
304
  static $surroundMixLevelLookup;
305
  if (empty($surroundMixLevelLookup)) {
@@ -313,6 +607,11 @@ class getid3_ac3 extends getid3_handler
313
  return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
314
  }
315
 
 
 
 
 
 
316
  public static function dolbySurroundModeLookup($dsurmod) {
317
  static $dolbySurroundModeLookup = array(
318
  0 => 'not indicated',
@@ -323,12 +622,18 @@ class getid3_ac3 extends getid3_handler
323
  return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
324
  }
325
 
 
 
 
 
 
 
326
  public static function channelsEnabledLookup($acmod, $lfeon) {
327
  $lookup = array(
328
- 'ch1'=>(bool) ($acmod == 0),
329
- 'ch2'=>(bool) ($acmod == 0),
330
- 'left'=>(bool) ($acmod > 1),
331
- 'right'=>(bool) ($acmod > 1),
332
  'center'=>(bool) ($acmod & 0x01),
333
  'surround_mono'=>false,
334
  'surround_left'=>false,
@@ -348,6 +653,11 @@ class getid3_ac3 extends getid3_handler
348
  return $lookup;
349
  }
350
 
 
 
 
 
 
351
  public static function heavyCompression($compre) {
352
  // The first four bits indicate gain changes in 6.02dB increments which can be
353
  // implemented with an arithmetic shift operation. The following four bits
@@ -398,6 +708,11 @@ class getid3_ac3 extends getid3_handler
398
  return $log_gain - $lin_gain;
399
  }
400
 
 
 
 
 
 
401
  public static function roomTypeLookup($roomtyp) {
402
  static $roomTypeLookup = array(
403
  0 => 'not indicated',
@@ -408,32 +723,39 @@ class getid3_ac3 extends getid3_handler
408
  return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
409
  }
410
 
 
 
 
 
 
 
411
  public static function frameSizeLookup($frmsizecod, $fscod) {
412
- $padding = (bool) ($frmsizecod % 2);
413
- $framesizeid = floor($frmsizecod / 2);
 
414
 
415
  static $frameSizeLookup = array();
416
  if (empty($frameSizeLookup)) {
417
  $frameSizeLookup = array (
418
- 0 => array(128, 138, 192),
419
- 1 => array(40, 160, 174, 240),
420
- 2 => array(48, 192, 208, 288),
421
- 3 => array(56, 224, 242, 336),
422
- 4 => array(64, 256, 278, 384),
423
- 5 => array(80, 320, 348, 480),
424
- 6 => array(96, 384, 416, 576),
425
- 7 => array(112, 448, 486, 672),
426
- 8 => array(128, 512, 556, 768),
427
- 9 => array(160, 640, 696, 960),
428
- 10 => array(192, 768, 834, 1152),
429
- 11 => array(224, 896, 974, 1344),
430
- 12 => array(256, 1024, 1114, 1536),
431
- 13 => array(320, 1280, 1392, 1920),
432
- 14 => array(384, 1536, 1670, 2304),
433
- 15 => array(448, 1792, 1950, 2688),
434
- 16 => array(512, 2048, 2228, 3072),
435
- 17 => array(576, 2304, 2506, 3456),
436
- 18 => array(640, 2560, 2786, 3840)
437
  );
438
  }
439
  if (($fscod == 1) && $padding) {
@@ -443,20 +765,27 @@ class getid3_ac3 extends getid3_handler
443
  return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
444
  }
445
 
 
 
 
 
 
446
  public static function bitrateLookup($frmsizecod) {
447
- $framesizeid = floor($frmsizecod / 2);
 
 
448
 
449
  static $bitrateLookup = array(
450
- 0 => 32000,
451
- 1 => 40000,
452
- 2 => 48000,
453
- 3 => 56000,
454
- 4 => 64000,
455
- 5 => 80000,
456
- 6 => 96000,
457
- 7 => 112000,
458
- 8 => 128000,
459
- 9 => 160000,
460
  10 => 192000,
461
  11 => 224000,
462
  12 => 256000,
@@ -465,10 +794,25 @@ class getid3_ac3 extends getid3_handler
465
  15 => 448000,
466
  16 => 512000,
467
  17 => 576000,
468
- 18 => 640000
469
  );
470
  return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
471
  }
472
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
 
474
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.ac3.php //
17
 
18
  class getid3_ac3 extends getid3_handler
19
  {
20
+ /**
21
+ * @var array
22
+ */
23
+ private $AC3header = array();
24
 
25
+ /**
26
+ * @var int
27
+ */
28
+ private $BSIoffset = 0;
29
 
30
+ const syncword = 0x0B77;
31
+
32
+ /**
33
+ * @return bool
34
+ */
35
  public function Analyze() {
36
  $info = &$this->getid3->info;
37
 
65
  // } /* end of syncinfo */
66
 
67
  $this->fseek($info['avdataoffset']);
68
+ $tempAC3header = $this->fread(100); // should be enough to cover all data, there are some variable-length fields...?
69
+ $this->AC3header['syncinfo'] = getid3_lib::BigEndian2Int(substr($tempAC3header, 0, 2));
70
+ $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin(substr($tempAC3header, 2));
71
+ $thisfile_ac3_raw_bsi['bsid'] = (getid3_lib::LittleEndian2Int(substr($tempAC3header, 5, 1)) & 0xF8) >> 3; // AC3 and E-AC3 put the "bsid" version identifier in the same place, but unfortnately the 4 bytes between the syncword and the version identifier are interpreted differently, so grab it here so the following code structure can make sense
72
+ unset($tempAC3header);
73
 
74
+ if ($this->AC3header['syncinfo'] !== self::syncword) {
 
 
 
75
  if (!$this->isDependencyFor('matroska')) {
76
  unset($info['fileformat'], $info['ac3']);
77
+ return $this->error('Expecting "'.dechex(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.dechex($this->AC3header['syncinfo']).'"');
78
  }
 
 
79
  }
80
 
81
  $info['audio']['dataformat'] = 'ac3';
82
  $info['audio']['bitrate_mode'] = 'cbr';
83
  $info['audio']['lossless'] = false;
84
 
85
+ if ($thisfile_ac3_raw_bsi['bsid'] <= 8) {
 
 
 
86
 
87
+ $thisfile_ac3_raw_bsi['crc1'] = getid3_lib::Bin2Dec($this->readHeaderBSI(16));
88
+ $thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2); // 5.4.1.3
89
+ $thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6); // 5.4.1.4
90
+ if ($thisfile_ac3_raw_bsi['frmsizecod'] > 37) { // binary: 100101 - see Table 5.18 Frame Size Code Table (1 word = 16 bits)
91
+ $this->warning('Unexpected ac3.bsi.frmsizecod value: '.$thisfile_ac3_raw_bsi['frmsizecod'].', bitrate not set correctly');
92
+ }
93
 
94
+ $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended
95
+ $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
96
+ $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
97
 
98
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
99
+ // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
100
+ $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
101
+ $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
102
+ }
103
 
104
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
105
+ // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
106
+ $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
107
+ $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
108
+ }
 
 
 
 
109
 
110
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
111
+ // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
112
+ $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
113
+ $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
114
+ }
115
 
116
+ $thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
+ // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
119
+ // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
120
+ $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); // 5.4.2.8 dialnorm: Dialogue Normalization, 5 Bits
 
 
121
 
122
+ $thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1); // 5.4.2.9 compre: Compression Gain Word Exists, 1 Bit
123
+ if ($thisfile_ac3_raw_bsi['flags']['compr']) {
124
+ $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); // 5.4.2.10 compr: Compression Gain Word, 8 Bits
125
+ $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
126
+ }
127
 
128
+ $thisfile_ac3_raw_bsi['flags']['langcod'] = (bool) $this->readHeaderBSI(1); // 5.4.2.11 langcode: Language Code Exists, 1 Bit
129
+ if ($thisfile_ac3_raw_bsi['flags']['langcod']) {
130
+ $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); // 5.4.2.12 langcod: Language Code, 8 Bits
131
+ }
 
132
 
133
+ $thisfile_ac3_raw_bsi['flags']['audprodinfo'] = (bool) $this->readHeaderBSI(1); // 5.4.2.13 audprodie: Audio Production Information Exists, 1 Bit
134
+ if ($thisfile_ac3_raw_bsi['flags']['audprodinfo']) {
135
+ $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); // 5.4.2.14 mixlevel: Mixing Level, 5 Bits
136
+ $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); // 5.4.2.15 roomtyp: Room Type, 2 Bits
 
 
137
 
138
+ $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
139
+ $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
140
+ }
141
 
 
 
 
 
142
 
143
+ $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); // 5.4.2.16 dialnorm2: Dialogue Normalization, ch2, 5 Bits
144
+ $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
 
 
 
145
 
146
+ $thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.17 compr2e: Compression Gain Word Exists, ch2, 1 Bit
147
+ if ($thisfile_ac3_raw_bsi['flags']['compr2']) {
148
+ $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); // 5.4.2.18 compr2: Compression Gain Word, ch2, 8 Bits
149
+ $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
150
+ }
151
 
152
+ $thisfile_ac3_raw_bsi['flags']['langcod2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.19 langcod2e: Language Code Exists, ch2, 1 Bit
153
+ if ($thisfile_ac3_raw_bsi['flags']['langcod2']) {
154
+ $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); // 5.4.2.20 langcod2: Language Code, ch2, 8 Bits
155
+ }
156
 
157
+ $thisfile_ac3_raw_bsi['flags']['audprodinfo2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.21 audprodi2e: Audio Production Information Exists, ch2, 1 Bit
158
+ if ($thisfile_ac3_raw_bsi['flags']['audprodinfo2']) {
159
+ $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); // 5.4.2.22 mixlevel2: Mixing Level, ch2, 5 Bits
160
+ $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); // 5.4.2.23 roomtyp2: Room Type, ch2, 2 Bits
161
+
162
+ $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
163
+ $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
164
+ }
165
 
166
+ $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); // 5.4.2.24 copyrightb: Copyright Bit, 1 Bit
 
 
 
167
 
168
+ $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); // 5.4.2.25 origbs: Original Bit Stream, 1 Bit
 
 
 
169
 
170
+ $thisfile_ac3_raw_bsi['flags']['timecod1'] = $this->readHeaderBSI(2); // 5.4.2.26 timecod1e, timcode2e: Time Code (first and second) Halves Exist, 2 Bits
171
+ if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x01) {
172
+ $thisfile_ac3_raw_bsi['timecod1'] = $this->readHeaderBSI(14); // 5.4.2.27 timecod1: Time code first half, 14 bits
173
+ $thisfile_ac3['timecode1'] = 0;
174
+ $thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x3E00) >> 9) * 3600; // The first 5 bits of this 14-bit field represent the time in hours, with valid values of 0�23
175
+ $thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x01F8) >> 3) * 60; // The next 6 bits represent the time in minutes, with valid values of 0�59
176
+ $thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x0003) >> 0) * 8; // The final 3 bits represents the time in 8 second increments, with valid values of 0�7 (representing 0, 8, 16, ... 56 seconds)
177
  }
178
+ if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x02) {
179
+ $thisfile_ac3_raw_bsi['timecod2'] = $this->readHeaderBSI(14); // 5.4.2.28 timecod2: Time code second half, 14 bits
180
+ $thisfile_ac3['timecode2'] = 0;
181
+ $thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x3800) >> 11) * 1; // The first 3 bits of this 14-bit field represent the time in seconds, with valid values from 0�7 (representing 0-7 seconds)
182
+ $thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x07C0) >> 6) * (1 / 30); // The next 5 bits represents the time in frames, with valid values from 0�29 (one frame = 1/30th of a second)
183
+ $thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x003F) >> 0) * ((1 / 30) / 60); // The final 6 bits represents fractions of 1/64 of a frame, with valid values from 0�63
184
  }
185
 
186
+ $thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1);
187
+ if ($thisfile_ac3_raw_bsi['flags']['addbsi']) {
188
+ $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6) + 1; // This 6-bit code, which exists only if addbside is a 1, indicates the length in bytes of additional bit stream information. The valid range of addbsil is 0�63, indicating 1�64 additional bytes, respectively.
 
189
 
190
+ $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
191
+
192
+ $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
193
+ $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
194
  }
195
 
 
196
 
197
+ } elseif ($thisfile_ac3_raw_bsi['bsid'] <= 16) { // E-AC3
198
 
 
199
 
200
+ $this->error('E-AC3 parsing is incomplete and experimental in this version of getID3 ('.$this->getid3->version().'). Notably the bitrate calculations are wrong -- value might (or not) be correct, but it is not calculated correctly. Email info@getid3.org if you know how to calculate EAC3 bitrate correctly.');
201
+ $info['audio']['dataformat'] = 'eac3';
202
+
203
+ $thisfile_ac3_raw_bsi['strmtyp'] = $this->readHeaderBSI(2);
204
+ $thisfile_ac3_raw_bsi['substreamid'] = $this->readHeaderBSI(3);
205
+ $thisfile_ac3_raw_bsi['frmsiz'] = $this->readHeaderBSI(11);
206
+ $thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2);
207
+ if ($thisfile_ac3_raw_bsi['fscod'] == 3) {
208
+ $thisfile_ac3_raw_bsi['fscod2'] = $this->readHeaderBSI(2);
209
+ $thisfile_ac3_raw_bsi['numblkscod'] = 3; // six blocks per syncframe
210
+ } else {
211
+ $thisfile_ac3_raw_bsi['numblkscod'] = $this->readHeaderBSI(2);
212
+ }
213
+ $thisfile_ac3['bsi']['blocks_per_sync_frame'] = self::blocksPerSyncFrame($thisfile_ac3_raw_bsi['numblkscod']);
214
+ $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
215
+ $thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1);
216
+ $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended
217
+ $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
218
+ $thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1);
219
+ if ($thisfile_ac3_raw_bsi['flags']['compr']) {
220
+ $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
221
+ }
222
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
223
+ $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
224
+ $thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1);
225
+ if ($thisfile_ac3_raw_bsi['flags']['compr2']) {
226
+ $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
227
+ }
228
+ }
229
+ if ($thisfile_ac3_raw_bsi['strmtyp'] == 1) { // if dependent stream
230
+ $thisfile_ac3_raw_bsi['flags']['chanmap'] = (bool) $this->readHeaderBSI(1);
231
+ if ($thisfile_ac3_raw_bsi['flags']['chanmap']) {
232
+ $thisfile_ac3_raw_bsi['chanmap'] = $this->readHeaderBSI(8);
233
+ }
234
+ }
235
+ $thisfile_ac3_raw_bsi['flags']['mixmdat'] = (bool) $this->readHeaderBSI(1);
236
+ if ($thisfile_ac3_raw_bsi['flags']['mixmdat']) { // Mixing metadata
237
+ if ($thisfile_ac3_raw_bsi['acmod'] > 2) { // if more than 2 channels
238
+ $thisfile_ac3_raw_bsi['dmixmod'] = $this->readHeaderBSI(2);
239
+ }
240
+ if (($thisfile_ac3_raw_bsi['acmod'] & 0x01) && ($thisfile_ac3_raw_bsi['acmod'] > 2)) { // if three front channels exist
241
+ $thisfile_ac3_raw_bsi['ltrtcmixlev'] = $this->readHeaderBSI(3);
242
+ $thisfile_ac3_raw_bsi['lorocmixlev'] = $this->readHeaderBSI(3);
243
+ }
244
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { // if a surround channel exists
245
+ $thisfile_ac3_raw_bsi['ltrtsurmixlev'] = $this->readHeaderBSI(3);
246
+ $thisfile_ac3_raw_bsi['lorosurmixlev'] = $this->readHeaderBSI(3);
247
+ }
248
+ if ($thisfile_ac3_raw_bsi['flags']['lfeon']) { // if the LFE channel exists
249
+ $thisfile_ac3_raw_bsi['flags']['lfemixlevcod'] = (bool) $this->readHeaderBSI(1);
250
+ if ($thisfile_ac3_raw_bsi['flags']['lfemixlevcod']) {
251
+ $thisfile_ac3_raw_bsi['lfemixlevcod'] = $this->readHeaderBSI(5);
252
+ }
253
+ }
254
+ if ($thisfile_ac3_raw_bsi['strmtyp'] == 0) { // if independent stream
255
+ $thisfile_ac3_raw_bsi['flags']['pgmscl'] = (bool) $this->readHeaderBSI(1);
256
+ if ($thisfile_ac3_raw_bsi['flags']['pgmscl']) {
257
+ $thisfile_ac3_raw_bsi['pgmscl'] = $this->readHeaderBSI(6);
258
+ }
259
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
260
+ $thisfile_ac3_raw_bsi['flags']['pgmscl2'] = (bool) $this->readHeaderBSI(1);
261
+ if ($thisfile_ac3_raw_bsi['flags']['pgmscl2']) {
262
+ $thisfile_ac3_raw_bsi['pgmscl2'] = $this->readHeaderBSI(6);
263
+ }
264
+ }
265
+ $thisfile_ac3_raw_bsi['flags']['extpgmscl'] = (bool) $this->readHeaderBSI(1);
266
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmscl']) {
267
+ $thisfile_ac3_raw_bsi['extpgmscl'] = $this->readHeaderBSI(6);
268
+ }
269
+ $thisfile_ac3_raw_bsi['mixdef'] = $this->readHeaderBSI(2);
270
+ if ($thisfile_ac3_raw_bsi['mixdef'] == 1) { // mixing option 2
271
+ $thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1);
272
+ $thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1);
273
+ $thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3);
274
+ } elseif ($thisfile_ac3_raw_bsi['mixdef'] == 2) { // mixing option 3
275
+ $thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI(12);
276
+ } elseif ($thisfile_ac3_raw_bsi['mixdef'] == 3) { // mixing option 4
277
+ $mixdefbitsread = 0;
278
+ $thisfile_ac3_raw_bsi['mixdeflen'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
279
+ $thisfile_ac3_raw_bsi['flags']['mixdata2'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
280
+ if ($thisfile_ac3_raw_bsi['flags']['mixdata2']) {
281
+ $thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
282
+ $thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
283
+ $thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3); $mixdefbitsread += 3;
284
+ $thisfile_ac3_raw_bsi['flags']['extpgmlscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
285
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmlscl']) {
286
+ $thisfile_ac3_raw_bsi['extpgmlscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
287
+ }
288
+ $thisfile_ac3_raw_bsi['flags']['extpgmcscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
289
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmcscl']) {
290
+ $thisfile_ac3_raw_bsi['extpgmcscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
291
+ }
292
+ $thisfile_ac3_raw_bsi['flags']['extpgmrscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
293
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmrscl']) {
294
+ $thisfile_ac3_raw_bsi['extpgmrscl'] = $this->readHeaderBSI(4);
295
+ }
296
+ $thisfile_ac3_raw_bsi['flags']['extpgmlsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
297
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmlsscl']) {
298
+ $thisfile_ac3_raw_bsi['extpgmlsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
299
+ }
300
+ $thisfile_ac3_raw_bsi['flags']['extpgmrsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
301
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmrsscl']) {
302
+ $thisfile_ac3_raw_bsi['extpgmrsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
303
+ }
304
+ $thisfile_ac3_raw_bsi['flags']['extpgmlfescl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
305
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmlfescl']) {
306
+ $thisfile_ac3_raw_bsi['extpgmlfescl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
307
+ }
308
+ $thisfile_ac3_raw_bsi['flags']['dmixscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
309
+ if ($thisfile_ac3_raw_bsi['flags']['dmixscl']) {
310
+ $thisfile_ac3_raw_bsi['dmixscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
311
+ }
312
+ $thisfile_ac3_raw_bsi['flags']['addch'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
313
+ if ($thisfile_ac3_raw_bsi['flags']['addch']) {
314
+ $thisfile_ac3_raw_bsi['flags']['extpgmaux1scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
315
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmaux1scl']) {
316
+ $thisfile_ac3_raw_bsi['extpgmaux1scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
317
+ }
318
+ $thisfile_ac3_raw_bsi['flags']['extpgmaux2scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
319
+ if ($thisfile_ac3_raw_bsi['flags']['extpgmaux2scl']) {
320
+ $thisfile_ac3_raw_bsi['extpgmaux2scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
321
+ }
322
+ }
323
+ }
324
+ $thisfile_ac3_raw_bsi['flags']['mixdata3'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
325
+ if ($thisfile_ac3_raw_bsi['flags']['mixdata3']) {
326
+ $thisfile_ac3_raw_bsi['spchdat'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
327
+ $thisfile_ac3_raw_bsi['flags']['addspchdat'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
328
+ if ($thisfile_ac3_raw_bsi['flags']['addspchdat']) {
329
+ $thisfile_ac3_raw_bsi['spchdat1'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
330
+ $thisfile_ac3_raw_bsi['spchan1att'] = $this->readHeaderBSI(2); $mixdefbitsread += 2;
331
+ $thisfile_ac3_raw_bsi['flags']['addspchdat1'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
332
+ if ($thisfile_ac3_raw_bsi['flags']['addspchdat1']) {
333
+ $thisfile_ac3_raw_bsi['spchdat2'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
334
+ $thisfile_ac3_raw_bsi['spchan2att'] = $this->readHeaderBSI(3); $mixdefbitsread += 3;
335
+ }
336
+ }
337
+ }
338
+ $mixdata_bits = (8 * ($thisfile_ac3_raw_bsi['mixdeflen'] + 2)) - $mixdefbitsread;
339
+ $mixdata_fill = (($mixdata_bits % 8) ? 8 - ($mixdata_bits % 8) : 0);
340
+ $thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI($mixdata_bits);
341
+ $thisfile_ac3_raw_bsi['mixdatafill'] = $this->readHeaderBSI($mixdata_fill);
342
+ unset($mixdefbitsread, $mixdata_bits, $mixdata_fill);
343
+ }
344
+ if ($thisfile_ac3_raw_bsi['acmod'] < 2) { // if mono or dual mono source
345
+ $thisfile_ac3_raw_bsi['flags']['paninfo'] = (bool) $this->readHeaderBSI(1);
346
+ if ($thisfile_ac3_raw_bsi['flags']['paninfo']) {
347
+ $thisfile_ac3_raw_bsi['panmean'] = $this->readHeaderBSI(8);
348
+ $thisfile_ac3_raw_bsi['paninfo'] = $this->readHeaderBSI(6);
349
+ }
350
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
351
+ $thisfile_ac3_raw_bsi['flags']['paninfo2'] = (bool) $this->readHeaderBSI(1);
352
+ if ($thisfile_ac3_raw_bsi['flags']['paninfo2']) {
353
+ $thisfile_ac3_raw_bsi['panmean2'] = $this->readHeaderBSI(8);
354
+ $thisfile_ac3_raw_bsi['paninfo2'] = $this->readHeaderBSI(6);
355
+ }
356
+ }
357
+ }
358
+ $thisfile_ac3_raw_bsi['flags']['frmmixcfginfo'] = (bool) $this->readHeaderBSI(1);
359
+ if ($thisfile_ac3_raw_bsi['flags']['frmmixcfginfo']) { // mixing configuration information
360
+ if ($thisfile_ac3_raw_bsi['numblkscod'] == 0) {
361
+ $thisfile_ac3_raw_bsi['blkmixcfginfo'][0] = $this->readHeaderBSI(5);
362
+ } else {
363
+ for ($blk = 0; $blk < $thisfile_ac3_raw_bsi['numblkscod']; $blk++) {
364
+ $thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk] = (bool) $this->readHeaderBSI(1);
365
+ if ($thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk]) { // mixing configuration information
366
+ $thisfile_ac3_raw_bsi['blkmixcfginfo'][$blk] = $this->readHeaderBSI(5);
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ }
373
+ $thisfile_ac3_raw_bsi['flags']['infomdat'] = (bool) $this->readHeaderBSI(1);
374
+ if ($thisfile_ac3_raw_bsi['flags']['infomdat']) { // Informational metadata
375
+ $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
376
+ $thisfile_ac3_raw_bsi['flags']['copyrightb'] = (bool) $this->readHeaderBSI(1);
377
+ $thisfile_ac3_raw_bsi['flags']['origbs'] = (bool) $this->readHeaderBSI(1);
378
+ if ($thisfile_ac3_raw_bsi['acmod'] == 2) { // if in 2/0 mode
379
+ $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
380
+ $thisfile_ac3_raw_bsi['dheadphonmod'] = $this->readHeaderBSI(2);
381
+ }
382
+ if ($thisfile_ac3_raw_bsi['acmod'] >= 6) { // if both surround channels exist
383
+ $thisfile_ac3_raw_bsi['dsurexmod'] = $this->readHeaderBSI(2);
384
+ }
385
+ $thisfile_ac3_raw_bsi['flags']['audprodi'] = (bool) $this->readHeaderBSI(1);
386
+ if ($thisfile_ac3_raw_bsi['flags']['audprodi']) {
387
+ $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
388
+ $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
389
+ $thisfile_ac3_raw_bsi['flags']['adconvtyp'] = (bool) $this->readHeaderBSI(1);
390
+ }
391
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
392
+ $thisfile_ac3_raw_bsi['flags']['audprodi2'] = (bool) $this->readHeaderBSI(1);
393
+ if ($thisfile_ac3_raw_bsi['flags']['audprodi2']) {
394
+ $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
395
+ $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
396
+ $thisfile_ac3_raw_bsi['flags']['adconvtyp2'] = (bool) $this->readHeaderBSI(1);
397
+ }
398
+ }
399
+ if ($thisfile_ac3_raw_bsi['fscod'] < 3) { // if not half sample rate
400
+ $thisfile_ac3_raw_bsi['flags']['sourcefscod'] = (bool) $this->readHeaderBSI(1);
401
+ }
402
+ }
403
+ if (($thisfile_ac3_raw_bsi['strmtyp'] == 0) && ($thisfile_ac3_raw_bsi['numblkscod'] != 3)) { // if both surround channels exist
404
+ $thisfile_ac3_raw_bsi['flags']['convsync'] = (bool) $this->readHeaderBSI(1);
405
+ }
406
+ if ($thisfile_ac3_raw_bsi['strmtyp'] == 2) { // if bit stream converted from AC-3
407
+ if ($thisfile_ac3_raw_bsi['numblkscod'] != 3) { // 6 blocks per syncframe
408
+ $thisfile_ac3_raw_bsi['flags']['blkid'] = 1;
409
+ } else {
410
+ $thisfile_ac3_raw_bsi['flags']['blkid'] = (bool) $this->readHeaderBSI(1);
411
+ }
412
+ if ($thisfile_ac3_raw_bsi['flags']['blkid']) {
413
+ $thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6);
414
+ }
415
+ }
416
+ $thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1);
417
+ if ($thisfile_ac3_raw_bsi['flags']['addbsi']) {
418
+ $thisfile_ac3_raw_bsi['addbsil'] = $this->readHeaderBSI(6);
419
+ $thisfile_ac3_raw_bsi['addbsi'] = $this->readHeaderBSI(($thisfile_ac3_raw_bsi['addbsil'] + 1) * 8);
420
+ }
421
+
422
+ } else {
423
+
424
+ $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 16. Please submit a support ticket with a sample file.');
425
+ unset($info['ac3']);
426
+ return false;
427
 
 
 
 
428
  }
429
 
430
+ if (isset($thisfile_ac3_raw_bsi['fscod2'])) {
431
+ $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup2($thisfile_ac3_raw_bsi['fscod2']);
432
+ } else {
433
+ $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw_bsi['fscod']);
434
+ }
435
+ if ($thisfile_ac3_raw_bsi['fscod'] <= 3) {
436
+ $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
437
+ } else {
438
+ $this->warning('Unexpected ac3.bsi.fscod value: '.$thisfile_ac3_raw_bsi['fscod']);
439
+ }
440
+ if (isset($thisfile_ac3_raw_bsi['frmsizecod'])) {
441
+ $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw_bsi['frmsizecod'], $thisfile_ac3_raw_bsi['fscod']);
442
+ $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw_bsi['frmsizecod']);
443
+ } elseif (!empty($thisfile_ac3_raw_bsi['frmsiz'])) {
444
+ // this isn't right, but it's (usually) close, roughly 5% less than it should be.
445
+ // but WHERE is the actual bitrate value stored in EAC3?? email info@getid3.org if you know!
446
+ $thisfile_ac3['bitrate'] = ($thisfile_ac3_raw_bsi['frmsiz'] + 1) * 16 * 30; // The frmsiz field shall contain a value one less than the overall size of the coded syncframe in 16-bit words. That is, this field may assume a value ranging from 0 to 2047, and these values correspond to syncframe sizes ranging from 1 to 2048.
447
+ // kludge-fix to make it approximately the expected value, still not "right":
448
+ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16000;
449
+ }
450
+ $info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
451
 
452
+ if (isset($thisfile_ac3_raw_bsi['bsmod']) && isset($thisfile_ac3_raw_bsi['acmod'])) {
453
+ $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
454
+ }
455
+ $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
456
+ foreach($ac3_coding_mode as $key => $value) {
457
+ $thisfile_ac3[$key] = $value;
458
+ }
459
+ switch ($thisfile_ac3_raw_bsi['acmod']) {
460
+ case 0:
461
+ case 1:
462
+ $info['audio']['channelmode'] = 'mono';
463
+ break;
464
+ case 3:
465
+ case 4:
466
+ $info['audio']['channelmode'] = 'stereo';
467
+ break;
468
+ default:
469
+ $info['audio']['channelmode'] = 'surround';
470
+ break;
471
+ }
472
+ $info['audio']['channels'] = $thisfile_ac3['num_channels'];
473
 
474
+ $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['flags']['lfeon'];
475
+ if ($thisfile_ac3_raw_bsi['flags']['lfeon']) {
476
+ $info['audio']['channels'] .= '.1';
477
  }
478
 
479
+ $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['flags']['lfeon']);
480
+ $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
481
+
482
  return true;
483
  }
484
 
485
+ /**
486
+ * @param int $length
487
+ *
488
+ * @return float|int
489
+ */
490
  private function readHeaderBSI($length) {
491
  $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
492
  $this->BSIoffset += $length;
494
  return bindec($data);
495
  }
496
 
497
+ /**
498
+ * @param int $fscod
499
+ *
500
+ * @return int|string|false
501
+ */
502
  public static function sampleRateCodeLookup($fscod) {
503
  static $sampleRateCodeLookup = array(
504
  0 => 48000,
509
  return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
510
  }
511
 
512
+ /**
513
+ * @param int $fscod2
514
+ *
515
+ * @return int|string|false
516
+ */
517
+ public static function sampleRateCodeLookup2($fscod2) {
518
+ static $sampleRateCodeLookup2 = array(
519
+ 0 => 24000,
520
+ 1 => 22050,
521
+ 2 => 16000,
522
+ 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
523
+ );
524
+ return (isset($sampleRateCodeLookup2[$fscod2]) ? $sampleRateCodeLookup2[$fscod2] : false);
525
+ }
526
+
527
+ /**
528
+ * @param int $bsmod
529
+ * @param int $acmod
530
+ *
531
+ * @return string|false
532
+ */
533
  public static function serviceTypeLookup($bsmod, $acmod) {
534
  static $serviceTypeLookup = array();
535
  if (empty($serviceTypeLookup)) {
551
  return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
552
  }
553
 
554
+ /**
555
+ * @param int $acmod
556
+ *
557
+ * @return array|false
558
+ */
559
  public static function audioCodingModeLookup($acmod) {
560
  // array(channel configuration, # channels (not incl LFE), channel order)
561
  static $audioCodingModeLookup = array (
571
  return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
572
  }
573
 
574
+ /**
575
+ * @param int $cmixlev
576
+ *
577
+ * @return int|float|string|false
578
+ */
579
  public static function centerMixLevelLookup($cmixlev) {
580
  static $centerMixLevelLookup;
581
  if (empty($centerMixLevelLookup)) {
589
  return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
590
  }
591
 
592
+ /**
593
+ * @param int $surmixlev
594
+ *
595
+ * @return int|float|string|false
596
+ */
597
  public static function surroundMixLevelLookup($surmixlev) {
598
  static $surroundMixLevelLookup;
599
  if (empty($surroundMixLevelLookup)) {
607
  return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
608
  }
609
 
610
+ /**
611
+ * @param int $dsurmod
612
+ *
613
+ * @return string|false
614
+ */
615
  public static function dolbySurroundModeLookup($dsurmod) {
616
  static $dolbySurroundModeLookup = array(
617
  0 => 'not indicated',
622
  return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
623
  }
624
 
625
+ /**
626
+ * @param int $acmod
627
+ * @param bool $lfeon
628
+ *
629
+ * @return array
630
+ */
631
  public static function channelsEnabledLookup($acmod, $lfeon) {
632
  $lookup = array(
633
+ 'ch1'=>($acmod == 0),
634
+ 'ch2'=>($acmod == 0),
635
+ 'left'=>($acmod > 1),
636
+ 'right'=>($acmod > 1),
637
  'center'=>(bool) ($acmod & 0x01),
638
  'surround_mono'=>false,
639
  'surround_left'=>false,
653
  return $lookup;
654
  }
655
 
656
+ /**
657
+ * @param int $compre
658
+ *
659
+ * @return float|int
660
+ */
661
  public static function heavyCompression($compre) {
662
  // The first four bits indicate gain changes in 6.02dB increments which can be
663
  // implemented with an arithmetic shift operation. The following four bits
708
  return $log_gain - $lin_gain;
709
  }
710
 
711
+ /**
712
+ * @param int $roomtyp
713
+ *
714
+ * @return string|false
715
+ */
716
  public static function roomTypeLookup($roomtyp) {
717
  static $roomTypeLookup = array(
718
  0 => 'not indicated',
723
  return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
724
  }
725
 
726
+ /**
727
+ * @param int $frmsizecod
728
+ * @param int $fscod
729
+ *
730
+ * @return int|false
731
+ */
732
  public static function frameSizeLookup($frmsizecod, $fscod) {
733
+ // LSB is whether padding is used or not
734
+ $padding = (bool) ($frmsizecod & 0x01);
735
+ $framesizeid = ($frmsizecod & 0x3E) >> 1;
736
 
737
  static $frameSizeLookup = array();
738
  if (empty($frameSizeLookup)) {
739
  $frameSizeLookup = array (
740
+ 0 => array( 128, 138, 192), // 32 kbps
741
+ 1 => array( 160, 174, 240), // 40 kbps
742
+ 2 => array( 192, 208, 288), // 48 kbps
743
+ 3 => array( 224, 242, 336), // 56 kbps
744
+ 4 => array( 256, 278, 384), // 64 kbps
745
+ 5 => array( 320, 348, 480), // 80 kbps
746
+ 6 => array( 384, 416, 576), // 96 kbps
747
+ 7 => array( 448, 486, 672), // 112 kbps
748
+ 8 => array( 512, 556, 768), // 128 kbps
749
+ 9 => array( 640, 696, 960), // 160 kbps
750
+ 10 => array( 768, 834, 1152), // 192 kbps
751
+ 11 => array( 896, 974, 1344), // 224 kbps
752
+ 12 => array(1024, 1114, 1536), // 256 kbps
753
+ 13 => array(1280, 1392, 1920), // 320 kbps
754
+ 14 => array(1536, 1670, 2304), // 384 kbps
755
+ 15 => array(1792, 1950, 2688), // 448 kbps
756
+ 16 => array(2048, 2228, 3072), // 512 kbps
757
+ 17 => array(2304, 2506, 3456), // 576 kbps
758
+ 18 => array(2560, 2786, 3840) // 640 kbps
759
  );
760
  }
761
  if (($fscod == 1) && $padding) {
765
  return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
766
  }
767
 
768
+ /**
769
+ * @param int $frmsizecod
770
+ *
771
+ * @return int|false
772
+ */
773
  public static function bitrateLookup($frmsizecod) {
774
+ // LSB is whether padding is used or not
775
+ $padding = (bool) ($frmsizecod & 0x01);
776
+ $framesizeid = ($frmsizecod & 0x3E) >> 1;
777
 
778
  static $bitrateLookup = array(
779
+ 0 => 32000,
780
+ 1 => 40000,
781
+ 2 => 48000,
782
+ 3 => 56000,
783
+ 4 => 64000,
784
+ 5 => 80000,
785
+ 6 => 96000,
786
+ 7 => 112000,
787
+ 8 => 128000,
788
+ 9 => 160000,
789
  10 => 192000,
790
  11 => 224000,
791
  12 => 256000,
794
  15 => 448000,
795
  16 => 512000,
796
  17 => 576000,
797
+ 18 => 640000,
798
  );
799
  return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
800
  }
801
 
802
+ /**
803
+ * @param int $numblkscod
804
+ *
805
+ * @return int|false
806
+ */
807
+ public static function blocksPerSyncFrame($numblkscod) {
808
+ static $blocksPerSyncFrameLookup = array(
809
+ 0 => 1,
810
+ 1 => 2,
811
+ 2 => 3,
812
+ 3 => 6,
813
+ );
814
+ return (isset($blocksPerSyncFrameLookup[$numblkscod]) ? $blocksPerSyncFrameLookup[$numblkscod] : false);
815
+ }
816
+
817
 
818
  }
lib/getid3/module.audio.amr.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.aa.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_amr extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -26,7 +28,7 @@ class getid3_amr extends getid3_handler
26
 
27
  $magic = '#!AMR'."\x0A";
28
  if (substr($AMRheader, 0, 6) != $magic) {
29
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"';
30
  return false;
31
  }
32
 
@@ -50,7 +52,6 @@ class getid3_amr extends getid3_handler
50
  $AMR_frame_header = ord(substr($buffer, 0, 1));
51
  $codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR.
52
  if ($codec_mode_request > 7) {
53
- $info['error'][] = '';
54
  break;
55
  }
56
  $thisfile_amr['frame_mode_count'][$codec_mode_request]++;
@@ -64,7 +65,11 @@ class getid3_amr extends getid3_handler
64
  return true;
65
  }
66
 
67
-
 
 
 
 
68
  public function amr_mode_bitrate($key) {
69
  static $amr_mode_bitrate = array(
70
  0 => 4750,
@@ -79,6 +84,11 @@ class getid3_amr extends getid3_handler
79
  return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
80
  }
81
 
 
 
 
 
 
82
  public function amr_mode_bytes_per_frame($key) {
83
  static $amr_mode_bitrate = array(
84
  0 => 13, // 1-byte frame header + 95 bits [padded to: 12 bytes] audio data
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.aa.php //
17
 
18
  class getid3_amr extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
28
 
29
  $magic = '#!AMR'."\x0A";
30
  if (substr($AMRheader, 0, 6) != $magic) {
31
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"');
32
  return false;
33
  }
34
 
52
  $AMR_frame_header = ord(substr($buffer, 0, 1));
53
  $codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR.
54
  if ($codec_mode_request > 7) {
 
55
  break;
56
  }
57
  $thisfile_amr['frame_mode_count'][$codec_mode_request]++;
65
  return true;
66
  }
67
 
68
+ /**
69
+ * @param int $key
70
+ *
71
+ * @return int|false
72
+ */
73
  public function amr_mode_bitrate($key) {
74
  static $amr_mode_bitrate = array(
75
  0 => 4750,
84
  return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
85
  }
86
 
87
+ /**
88
+ * @param int $key
89
+ *
90
+ * @return int|false
91
+ */
92
  public function amr_mode_bytes_per_frame($key) {
93
  static $amr_mode_bitrate = array(
94
  0 => 13, // 1-byte frame header + 95 bits [padded to: 12 bytes] audio data
lib/getid3/module.audio.au.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.au.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_au extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -26,7 +28,7 @@ class getid3_au extends getid3_handler
26
 
27
  $magic = '.snd';
28
  if (substr($AUheader, 0, 4) != $magic) {
29
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"';
30
  return false;
31
  }
32
 
@@ -61,7 +63,7 @@ class getid3_au extends getid3_handler
61
  $info['audio']['channels'] = $thisfile_au['channels'];
62
 
63
  if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) {
64
- $info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"';
65
  }
66
 
67
  $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
@@ -70,6 +72,11 @@ class getid3_au extends getid3_handler
70
  return true;
71
  }
72
 
 
 
 
 
 
73
  public function AUdataFormatNameLookup($id) {
74
  static $AUdataFormatNameLookup = array(
75
  0 => 'unspecified format',
@@ -104,6 +111,11 @@ class getid3_au extends getid3_handler
104
  return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false);
105
  }
106
 
 
 
 
 
 
107
  public function AUdataFormatBitsPerSampleLookup($id) {
108
  static $AUdataFormatBitsPerSampleLookup = array(
109
  1 => 8,
@@ -132,6 +144,11 @@ class getid3_au extends getid3_handler
132
  return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false);
133
  }
134
 
 
 
 
 
 
135
  public function AUdataFormatUsedBitsPerSampleLookup($id) {
136
  static $AUdataFormatUsedBitsPerSampleLookup = array(
137
  1 => 8,
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.au.php //
17
 
18
  class getid3_au extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
28
 
29
  $magic = '.snd';
30
  if (substr($AUheader, 0, 4) != $magic) {
31
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"');
32
  return false;
33
  }
34
 
63
  $info['audio']['channels'] = $thisfile_au['channels'];
64
 
65
  if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) {
66
+ $this->warning('Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
67
  }
68
 
69
  $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
72
  return true;
73
  }
74
 
75
+ /**
76
+ * @param int $id
77
+ *
78
+ * @return string|false
79
+ */
80
  public function AUdataFormatNameLookup($id) {
81
  static $AUdataFormatNameLookup = array(
82
  0 => 'unspecified format',
111
  return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false);
112
  }
113
 
114
+ /**
115
+ * @param int $id
116
+ *
117
+ * @return int|false
118
+ */
119
  public function AUdataFormatBitsPerSampleLookup($id) {
120
  static $AUdataFormatBitsPerSampleLookup = array(
121
  1 => 8,
144
  return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false);
145
  }
146
 
147
+ /**
148
+ * @param int $id
149
+ *
150
+ * @return int|false
151
+ */
152
  public function AUdataFormatUsedBitsPerSampleLookup($id) {
153
  static $AUdataFormatUsedBitsPerSampleLookup = array(
154
  1 => 8,
lib/getid3/module.audio.avr.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.avr.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_avr extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -69,7 +71,7 @@ class getid3_avr extends getid3_handler
69
  $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
70
  $magic = '2BIT';
71
  if ($info['avr']['raw']['magic'] != $magic) {
72
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"';
73
  unset($info['fileformat']);
74
  unset($info['avr']);
75
  return false;
@@ -106,7 +108,7 @@ class getid3_avr extends getid3_handler
106
  }
107
 
108
  if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
109
- $info['warning'][] = 'Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']);
110
  }
111
 
112
  $info['audio']['dataformat'] = 'avr';
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.avr.php //
17
 
18
  class getid3_avr extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
71
  $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
72
  $magic = '2BIT';
73
  if ($info['avr']['raw']['magic'] != $magic) {
74
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"');
75
  unset($info['fileformat']);
76
  unset($info['avr']);
77
  return false;
108
  }
109
 
110
  if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
111
+ $this->warning('Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']));
112
  }
113
 
114
  $info['audio']['dataformat'] = 'avr';
lib/getid3/module.audio.bonk.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.la.php //
@@ -17,6 +17,9 @@
17
 
18
  class getid3_bonk extends getid3_handler
19
  {
 
 
 
20
  public function Analyze() {
21
  $info = &$this->getid3->info;
22
 
@@ -29,7 +32,7 @@ class getid3_bonk extends getid3_handler
29
 
30
  if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) {
31
 
32
- $info['warning'][] = 'Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to '.round(PHP_INT_MAX / 1073741824).'GB';
33
 
34
  } else {
35
 
@@ -42,7 +45,7 @@ class getid3_bonk extends getid3_handler
42
  $BonkTagOffset = $this->ftell();
43
  $TagHeaderTest = $this->fread(5);
44
  if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
45
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"';
46
  return false;
47
  }
48
  $BonkTagName = substr($TagHeaderTest, 1, 4);
@@ -114,6 +117,9 @@ class getid3_bonk extends getid3_handler
114
 
115
  }
116
 
 
 
 
117
  public function HandleBonkTags($BonkTagName) {
118
  $info = &$this->getid3->info;
119
  switch ($BonkTagName) {
@@ -207,12 +213,18 @@ class getid3_bonk extends getid3_handler
207
  break;
208
 
209
  default:
210
- $info['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset'];
211
  break;
212
 
213
  }
214
  }
215
 
 
 
 
 
 
 
216
  public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) {
217
  static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META');
218
  foreach ($BonkIsValidTagName as $validtagname) {
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.la.php //
17
 
18
  class getid3_bonk extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
32
 
33
  if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) {
34
 
35
+ $this->warning('Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to '.round(PHP_INT_MAX / 1073741824).'GB');
36
 
37
  } else {
38
 
45
  $BonkTagOffset = $this->ftell();
46
  $TagHeaderTest = $this->fread(5);
47
  if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
48
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"');
49
  return false;
50
  }
51
  $BonkTagName = substr($TagHeaderTest, 1, 4);
117
 
118
  }
119
 
120
+ /**
121
+ * @param string $BonkTagName
122
+ */
123
  public function HandleBonkTags($BonkTagName) {
124
  $info = &$this->getid3->info;
125
  switch ($BonkTagName) {
213
  break;
214
 
215
  default:
216
+ $this->warning('Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset']);
217
  break;
218
 
219
  }
220
  }
221
 
222
+ /**
223
+ * @param string $PossibleBonkTag
224
+ * @param bool $ignorecase
225
+ *
226
+ * @return bool
227
+ */
228
  public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) {
229
  static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META');
230
  foreach ($BonkIsValidTagName as $validtagname) {
lib/getid3/module.audio.dsf.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /////////////////////////////////////////////////////////////////
4
+ /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
9
+ /////////////////////////////////////////////////////////////////
10
+ // //
11
+ // module.audio.dsf.php //
12
+ // module for analyzing dsf/DSF Audio files //
13
+ // dependencies: module.tag.id3v2.php //
14
+ // ///
15
+ /////////////////////////////////////////////////////////////////
16
+
17
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
18
+
19
+ class getid3_dsf extends getid3_handler
20
+ {
21
+ /**
22
+ * @return bool
23
+ */
24
+ public function Analyze() {
25
+ $info = &$this->getid3->info;
26
+
27
+ $info['fileformat'] = 'dsf';
28
+ $info['audio']['dataformat'] = 'dsf';
29
+ $info['audio']['lossless'] = true;
30
+ $info['audio']['bitrate_mode'] = 'cbr';
31
+
32
+ $this->fseek($info['avdataoffset']);
33
+ $dsfheader = $this->fread(28 + 12);
34
+
35
+ $headeroffset = 0;
36
+ $info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4);
37
+ $headeroffset += 4;
38
+ $magic = 'DSD ';
39
+ if ($info['dsf']['dsd']['magic'] != $magic) {
40
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"');
41
+ unset($info['fileformat']);
42
+ unset($info['audio']);
43
+ unset($info['dsf']);
44
+ return false;
45
+ }
46
+ $info['dsf']['dsd']['dsd_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28
47
+ $headeroffset += 8;
48
+ $info['dsf']['dsd']['dsf_file_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
49
+ $headeroffset += 8;
50
+ $info['dsf']['dsd']['meta_chunk_offset'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
51
+ $headeroffset += 8;
52
+
53
+
54
+ $info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4);
55
+ $headeroffset += 4;
56
+ $magic = 'fmt ';
57
+ if ($info['dsf']['fmt']['magic'] != $magic) {
58
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"');
59
+ return false;
60
+ }
61
+ $info['dsf']['fmt']['fmt_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // usually 52 bytes
62
+ $headeroffset += 8;
63
+ $dsfheader .= $this->fread($info['dsf']['fmt']['fmt_chunk_size'] - 12 + 12); // we have already read the entire DSD chunk, plus 12 bytes of FMT. We now want to read the size of FMT, plus 12 bytes into the next chunk to get magic and size.
64
+ if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) {
65
+ $this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes');
66
+ return false;
67
+ }
68
+ $info['dsf']['fmt']['format_version'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "1"
69
+ $headeroffset += 4;
70
+ $info['dsf']['fmt']['format_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "0" = "DSD Raw"
71
+ $headeroffset += 4;
72
+ $info['dsf']['fmt']['channel_type_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
73
+ $headeroffset += 4;
74
+ $info['dsf']['fmt']['channels'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
75
+ $headeroffset += 4;
76
+ $info['dsf']['fmt']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
77
+ $headeroffset += 4;
78
+ $info['dsf']['fmt']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
79
+ $headeroffset += 4;
80
+ $info['dsf']['fmt']['sample_count'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
81
+ $headeroffset += 8;
82
+ $info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
83
+ $headeroffset += 4;
84
+ $info['dsf']['fmt']['reserved'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled
85
+ $headeroffset += 4;
86
+
87
+
88
+ $info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4);
89
+ $headeroffset += 4;
90
+ $magic = 'data';
91
+ if ($info['dsf']['data']['magic'] != $magic) {
92
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"');
93
+ return false;
94
+ }
95
+ $info['dsf']['data']['data_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
96
+ $headeroffset += 8;
97
+ $info['avdataoffset'] = $headeroffset;
98
+ $info['avdataend'] = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size'];
99
+
100
+
101
+ if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) {
102
+ $getid3_id3v2 = new getid3_id3v2($this->getid3);
103
+ $getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset'];
104
+ $getid3_id3v2->Analyze();
105
+ unset($getid3_id3v2);
106
+ }
107
+
108
+
109
+ $info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']);
110
+ $info['audio']['channelmode'] = $info['dsf']['fmt']['channel_type'];
111
+ $info['audio']['bits_per_sample'] = $info['dsf']['fmt']['bits_per_sample'];
112
+ $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate'];
113
+ $info['audio']['channels'] = $info['dsf']['fmt']['channels'];
114
+ $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
115
+ $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
116
+
117
+ return true;
118
+ }
119
+
120
+ /**
121
+ * @param int $channel_type_id
122
+ *
123
+ * @return string
124
+ */
125
+ public static function DSFchannelTypeLookup($channel_type_id) {
126
+ static $DSFchannelTypeLookup = array(
127
+ // interleaving order:
128
+ 1 => 'mono', // 1: Mono
129
+ 2 => 'stereo', // 1: Front-Left; 2: Front-Right
130
+ 3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center
131
+ 4 => 'quad', // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right
132
+ 5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency
133
+ 6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Back-Left 5: Back-Right
134
+ 7 => '5.1', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency; 5: Back-Left; 6: Back-Right
135
+ );
136
+ return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : '');
137
+ }
138
+
139
+ }
lib/getid3/module.audio.dss.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.dss.php //
@@ -17,15 +17,17 @@
17
 
18
  class getid3_dss extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
24
  $this->fseek($info['avdataoffset']);
25
  $DSSheader = $this->fread(1540);
26
 
27
- if (!preg_match('#^(\x02|\x03)ds[s2]#', $DSSheader)) {
28
- $info['error'][] = 'Expecting "[02-03] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"';
29
  return false;
30
  }
31
 
@@ -38,33 +40,44 @@ class getid3_dss extends getid3_handler
38
  $info['audio']['dataformat'] = substr($DSSheader, 1, 3); // "dss" or "ds2"
39
  $info['audio']['bitrate_mode'] = 'cbr';
40
 
41
- $info['dss']['version'] = ord(substr($DSSheader, 0, 1));
42
- $info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400"
43
- $info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4));
44
  // 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen
45
- $info['dss']['date_create'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
46
- $info['dss']['date_complete'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
47
- $info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS
48
- $info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512
49
- $info['dss']['priority'] = ord(substr($DSSheader, 793, 1));
50
- $info['dss']['comments'] = trim(substr($DSSheader, 798, 100));
51
- $info['dss']['sample_rate_index'] = ord(substr($DSSheader, 1538, 1)); // this isn't certain, this may or may not be where the sample rate info is stored, but it seems consistent on my small selection of sample files
 
 
 
 
 
52
 
53
  $info['audio']['bits_per_sample'] = 16; // maybe, maybe not -- most compressed audio formats don't have a fixed bits-per-sample value, but this is a reasonable approximation
54
- $info['audio']['sample_rate'] = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']);
55
  $info['audio']['channels'] = 1;
56
 
57
- $info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000;
58
- if (floor($info['dss']['playtime_ms'] / 1000) != $info['dss']['playtime_sec']) {
59
- // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check
60
  $info['playtime_seconds'] = $info['dss']['playtime_sec'];
61
- $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value');
 
 
62
  }
63
  $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds'];
64
 
65
  return true;
66
  }
67
 
 
 
 
 
 
68
  public function DSSdateStringToUnixDate($datestring) {
69
  $y = substr($datestring, 0, 2);
70
  $m = substr($datestring, 2, 2);
@@ -76,6 +89,11 @@ class getid3_dss extends getid3_handler
76
  return mktime($h, $i, $s, $m, $d, $y);
77
  }
78
 
 
 
 
 
 
79
  public function DSSsampleRateLookup($sample_rate_index) {
80
  static $dssSampleRateLookup = array(
81
  0x0A => 16000,
@@ -84,7 +102,7 @@ class getid3_dss extends getid3_handler
84
  0x15 => 8000,
85
  );
86
  if (!array_key_exists($sample_rate_index, $dssSampleRateLookup)) {
87
- $this->getid3->warning('unknown sample_rate_index: '.$sample_rate_index);
88
  return false;
89
  }
90
  return $dssSampleRateLookup[$sample_rate_index];
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.dss.php //
17
 
18
  class getid3_dss extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
26
  $this->fseek($info['avdataoffset']);
27
  $DSSheader = $this->fread(1540);
28
 
29
+ if (!preg_match('#^[\\x02-\\x06]ds[s2]#', $DSSheader)) {
30
+ $this->error('Expecting "[02-06] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"');
31
  return false;
32
  }
33
 
40
  $info['audio']['dataformat'] = substr($DSSheader, 1, 3); // "dss" or "ds2"
41
  $info['audio']['bitrate_mode'] = 'cbr';
42
 
43
+ $info['dss']['version'] = ord(substr($DSSheader, 0, 1));
44
+ $info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400"
45
+ $info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4));
46
  // 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen
47
+ $info['dss']['date_create_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
48
+ $info['dss']['date_complete_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
49
+ $info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS
50
+ if ($info['dss']['version'] <= 3) {
51
+ $info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512
52
+ $info['dss']['priority'] = ord(substr($DSSheader, 793, 1));
53
+ $info['dss']['comments'] = trim(substr($DSSheader, 798, 100));
54
+ $info['dss']['sample_rate_index'] = ord(substr($DSSheader, 1538, 1)); // this isn't certain, this may or may not be where the sample rate info is stored, but it seems consistent on my small selection of sample files
55
+ $info['audio']['sample_rate'] = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']);
56
+ } else {
57
+ $this->getid3->warning('DSS above version 3 not fully supported in this version of getID3. Any additional documentation or format specifications would be welcome. This file is version '.$info['dss']['version']);
58
+ }
59
 
60
  $info['audio']['bits_per_sample'] = 16; // maybe, maybe not -- most compressed audio formats don't have a fixed bits-per-sample value, but this is a reasonable approximation
 
61
  $info['audio']['channels'] = 1;
62
 
63
+ if (!empty($info['dss']['playtime_ms']) && (floor($info['dss']['playtime_ms'] / 1000) == $info['dss']['playtime_sec'])) { // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check
64
+ $info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000;
65
+ } else {
66
  $info['playtime_seconds'] = $info['dss']['playtime_sec'];
67
+ if (!empty($info['dss']['playtime_ms'])) {
68
+ $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value');
69
+ }
70
  }
71
  $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds'];
72
 
73
  return true;
74
  }
75
 
76
+ /**
77
+ * @param string $datestring
78
+ *
79
+ * @return int|false
80
+ */
81
  public function DSSdateStringToUnixDate($datestring) {
82
  $y = substr($datestring, 0, 2);
83
  $m = substr($datestring, 2, 2);
89
  return mktime($h, $i, $s, $m, $d, $y);
90
  }
91
 
92
+ /**
93
+ * @param int $sample_rate_index
94
+ *
95
+ * @return int|false
96
+ */
97
  public function DSSsampleRateLookup($sample_rate_index) {
98
  static $dssSampleRateLookup = array(
99
  0x0A => 16000,
102
  0x15 => 8000,
103
  );
104
  if (!array_key_exists($sample_rate_index, $dssSampleRateLookup)) {
105
+ $this->getid3->warning('unknown sample_rate_index: 0x'.strtoupper(dechex($sample_rate_index)));
106
  return false;
107
  }
108
  return $dssSampleRateLookup[$sample_rate_index];
lib/getid3/module.audio.dts.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.dts.php //
@@ -21,21 +21,27 @@
21
  class getid3_dts extends getid3_handler
22
  {
23
  /**
24
- * Default DTS syncword used in native .cpt or .dts formats
25
- */
26
- const syncword = "\x7F\xFE\x80\x01";
27
 
 
 
 
28
  private $readBinDataOffset = 0;
29
 
30
- /**
31
- * Possible syncwords indicating bitstream encoding
32
- */
33
- public static $syncwords = array(
34
- 0 => "\x7F\xFE\x80\x01", // raw big-endian
35
- 1 => "\xFE\x7F\x01\x80", // raw little-endian
36
- 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian
37
- 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
38
 
 
 
 
39
  public function Analyze() {
40
  $info = &$this->getid3->info;
41
  $info['fileformat'] = 'dts';
@@ -45,18 +51,18 @@ class getid3_dts extends getid3_handler
45
 
46
  // check syncword
47
  $sync = substr($DTSheader, 0, 4);
48
- if (($encoding = array_search($sync, self::$syncwords)) !== false) {
49
 
50
- $info['dts']['raw']['magic'] = $sync;
51
  $this->readBinDataOffset = 32;
52
 
53
- } elseif ($this->isDependencyFor('matroska')) {
54
 
55
  // Matroska contains DTS without syncword encoded as raw big-endian format
56
  $encoding = 0;
57
  $this->readBinDataOffset = 0;
58
 
59
- } else {
60
 
61
  unset($info['fileformat']);
62
  return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
@@ -139,6 +145,12 @@ class getid3_dts extends getid3_handler
139
  return true;
140
  }
141
 
 
 
 
 
 
 
142
  private function readBinData($bin, $length) {
143
  $data = substr($bin, $this->readBinDataOffset, $length);
144
  $this->readBinDataOffset += $length;
@@ -146,6 +158,11 @@ class getid3_dts extends getid3_handler
146
  return bindec($data);
147
  }
148
 
 
 
 
 
 
149
  public static function bitrateLookup($index) {
150
  static $lookup = array(
151
  0 => 32000,
@@ -184,6 +201,11 @@ class getid3_dts extends getid3_handler
184
  return (isset($lookup[$index]) ? $lookup[$index] : false);
185
  }
186
 
 
 
 
 
 
187
  public static function sampleRateLookup($index) {
188
  static $lookup = array(
189
  0 => 'invalid',
@@ -206,6 +228,11 @@ class getid3_dts extends getid3_handler
206
  return (isset($lookup[$index]) ? $lookup[$index] : false);
207
  }
208
 
 
 
 
 
 
209
  public static function bitPerSampleLookup($index) {
210
  static $lookup = array(
211
  0 => 16,
@@ -216,6 +243,11 @@ class getid3_dts extends getid3_handler
216
  return (isset($lookup[$index]) ? $lookup[$index] : false);
217
  }
218
 
 
 
 
 
 
219
  public static function numChannelsLookup($index) {
220
  switch ($index) {
221
  case 0:
@@ -254,6 +286,11 @@ class getid3_dts extends getid3_handler
254
  return false;
255
  }
256
 
 
 
 
 
 
257
  public static function channelArrangementLookup($index) {
258
  static $lookup = array(
259
  0 => 'A',
@@ -276,6 +313,12 @@ class getid3_dts extends getid3_handler
276
  return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined');
277
  }
278
 
 
 
 
 
 
 
279
  public static function dialogNormalization($index, $version) {
280
  switch ($version) {
281
  case 7:
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.dts.php //
21
  class getid3_dts extends getid3_handler
22
  {
23
  /**
24
+ * Default DTS syncword used in native .cpt or .dts formats.
25
+ */
26
+ const syncword = "\x7F\xFE\x80\x01";
27
 
28
+ /**
29
+ * @var int
30
+ */
31
  private $readBinDataOffset = 0;
32
 
33
+ /**
34
+ * Possible syncwords indicating bitstream encoding.
35
+ */
36
+ public static $syncwords = array(
37
+ 0 => "\x7F\xFE\x80\x01", // raw big-endian
38
+ 1 => "\xFE\x7F\x01\x80", // raw little-endian
39
+ 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian
40
+ 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
41
 
42
+ /**
43
+ * @return bool
44
+ */
45
  public function Analyze() {
46
  $info = &$this->getid3->info;
47
  $info['fileformat'] = 'dts';
51
 
52
  // check syncword
53
  $sync = substr($DTSheader, 0, 4);
54
+ if (($encoding = array_search($sync, self::$syncwords)) !== false) {
55
 
56
+ $info['dts']['raw']['magic'] = $sync;
57
  $this->readBinDataOffset = 32;
58
 
59
+ } elseif ($this->isDependencyFor('matroska')) {
60
 
61
  // Matroska contains DTS without syncword encoded as raw big-endian format
62
  $encoding = 0;
63
  $this->readBinDataOffset = 0;
64
 
65
+ } else {
66
 
67
  unset($info['fileformat']);
68
  return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
145
  return true;
146
  }
147
 
148
+ /**
149
+ * @param string $bin
150
+ * @param int $length
151
+ *
152
+ * @return float|int
153
+ */
154
  private function readBinData($bin, $length) {
155
  $data = substr($bin, $this->readBinDataOffset, $length);
156
  $this->readBinDataOffset += $length;
158
  return bindec($data);
159
  }
160
 
161
+ /**
162
+ * @param int $index
163
+ *
164
+ * @return int|string|false
165
+ */
166
  public static function bitrateLookup($index) {
167
  static $lookup = array(
168
  0 => 32000,
201
  return (isset($lookup[$index]) ? $lookup[$index] : false);
202
  }
203
 
204
+ /**
205
+ * @param int $index
206
+ *
207
+ * @return int|string|false
208
+ */
209
  public static function sampleRateLookup($index) {
210
  static $lookup = array(
211
  0 => 'invalid',
228
  return (isset($lookup[$index]) ? $lookup[$index] : false);
229
  }
230
 
231
+ /**
232
+ * @param int $index
233
+ *
234
+ * @return int|false
235
+ */
236
  public static function bitPerSampleLookup($index) {
237
  static $lookup = array(
238
  0 => 16,
243
  return (isset($lookup[$index]) ? $lookup[$index] : false);
244
  }
245
 
246
+ /**
247
+ * @param int $index
248
+ *
249
+ * @return int|false
250
+ */
251
  public static function numChannelsLookup($index) {
252
  switch ($index) {
253
  case 0:
286
  return false;
287
  }
288
 
289
+ /**
290
+ * @param int $index
291
+ *
292
+ * @return string
293
+ */
294
  public static function channelArrangementLookup($index) {
295
  static $lookup = array(
296
  0 => 'A',
313
  return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined');
314
  }
315
 
316
+ /**
317
+ * @param int $index
318
+ * @param int $version
319
+ *
320
+ * @return int|false
321
+ */
322
  public static function dialogNormalization($index, $version) {
323
  switch ($version) {
324
  case 7:
lib/getid3/module.audio.flac.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.flac.php //
@@ -24,6 +24,9 @@ class getid3_flac extends getid3_handler
24
  {
25
  const syncword = 'fLaC';
26
 
 
 
 
27
  public function Analyze() {
28
  $info = &$this->getid3->info;
29
 
@@ -41,22 +44,30 @@ class getid3_flac extends getid3_handler
41
  return $this->parseMETAdata();
42
  }
43
 
 
 
 
44
  public function parseMETAdata() {
45
  $info = &$this->getid3->info;
46
  do {
47
  $BlockOffset = $this->ftell();
48
  $BlockHeader = $this->fread(4);
49
- $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));
50
  $LastBlockFlag = (bool) ($LBFBT & 0x80);
51
  $BlockType = ($LBFBT & 0x7F);
52
  $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
53
  $BlockTypeText = self::metaBlockTypeLookup($BlockType);
54
 
55
  if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
56
- $this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
57
  break;
58
  }
59
  if ($BlockLength < 1) {
 
 
 
 
 
60
  $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
61
  break;
62
  }
@@ -167,7 +178,7 @@ class getid3_flac extends getid3_handler
167
  if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
168
 
169
  if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
170
- $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
171
  }
172
  else {
173
  $info['md5_data_source'] = '';
@@ -194,12 +205,14 @@ class getid3_flac extends getid3_handler
194
  return true;
195
  }
196
 
197
- private function parseSTREAMINFO($BlockData) {
198
- $info = &$this->getid3->info;
199
-
200
- $info['flac']['STREAMINFO'] = array();
201
- $streaminfo = &$info['flac']['STREAMINFO'];
202
 
 
 
 
 
 
 
 
203
  $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
204
  $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
205
  $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
@@ -211,15 +224,28 @@ class getid3_flac extends getid3_handler
211
  $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1;
212
  $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
213
 
214
- $streaminfo['audio_signature'] = substr($BlockData, 18, 16);
 
 
 
 
 
 
 
 
 
 
 
215
 
216
- if (!empty($streaminfo['sample_rate'])) {
 
 
217
 
218
  $info['audio']['bitrate_mode'] = 'vbr';
219
- $info['audio']['sample_rate'] = $streaminfo['sample_rate'];
220
- $info['audio']['channels'] = $streaminfo['channels'];
221
- $info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample'];
222
- $info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate'];
223
  if ($info['playtime_seconds'] > 0) {
224
  if (!$this->isDependencyFor('matroska')) {
225
  $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
@@ -236,6 +262,11 @@ class getid3_flac extends getid3_handler
236
  return true;
237
  }
238
 
 
 
 
 
 
239
  private function parseAPPLICATION($BlockData) {
240
  $info = &$this->getid3->info;
241
 
@@ -246,6 +277,11 @@ class getid3_flac extends getid3_handler
246
  return true;
247
  }
248
 
 
 
 
 
 
249
  private function parseSEEKTABLE($BlockData) {
250
  $info = &$this->getid3->info;
251
 
@@ -275,6 +311,11 @@ class getid3_flac extends getid3_handler
275
  return true;
276
  }
277
 
 
 
 
 
 
278
  private function parseVORBIS_COMMENT($BlockData) {
279
  $info = &$this->getid3->info;
280
 
@@ -294,6 +335,11 @@ class getid3_flac extends getid3_handler
294
  return true;
295
  }
296
 
 
 
 
 
 
297
  private function parseCUESHEET($BlockData) {
298
  $info = &$this->getid3->info;
299
  $offset = 0;
@@ -346,9 +392,11 @@ class getid3_flac extends getid3_handler
346
  }
347
 
348
  /**
349
- * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
350
- * External usage: audio.ogg
351
- */
 
 
352
  public function parsePICTURE() {
353
  $info = &$this->getid3->info;
354
 
@@ -380,6 +428,11 @@ class getid3_flac extends getid3_handler
380
  return true;
381
  }
382
 
 
 
 
 
 
383
  public static function metaBlockTypeLookup($blocktype) {
384
  static $lookup = array(
385
  0 => 'STREAMINFO',
@@ -393,6 +446,11 @@ class getid3_flac extends getid3_handler
393
  return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
394
  }
395
 
 
 
 
 
 
396
  public static function applicationIDLookup($applicationid) {
397
  // http://flac.sourceforge.net/id.html
398
  static $lookup = array(
@@ -423,6 +481,11 @@ class getid3_flac extends getid3_handler
423
  return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
424
  }
425
 
 
 
 
 
 
426
  public static function pictureTypeLookup($type_id) {
427
  static $lookup = array (
428
  0 => 'Other',
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.flac.php //
24
  {
25
  const syncword = 'fLaC';
26
 
27
+ /**
28
+ * @return bool
29
+ */
30
  public function Analyze() {
31
  $info = &$this->getid3->info;
32
 
44
  return $this->parseMETAdata();
45
  }
46
 
47
+ /**
48
+ * @return bool
49
+ */
50
  public function parseMETAdata() {
51
  $info = &$this->getid3->info;
52
  do {
53
  $BlockOffset = $this->ftell();
54
  $BlockHeader = $this->fread(4);
55
+ $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1)); // LBFBT = LastBlockFlag + BlockType
56
  $LastBlockFlag = (bool) ($LBFBT & 0x80);
57
  $BlockType = ($LBFBT & 0x7F);
58
  $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
59
  $BlockTypeText = self::metaBlockTypeLookup($BlockType);
60
 
61
  if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
62
+ $this->warning('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
63
  break;
64
  }
65
  if ($BlockLength < 1) {
66
+ if ($BlockTypeText != 'reserved') {
67
+ // probably supposed to be zero-length
68
+ $this->warning('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockTypeText.') at offset '.$BlockOffset.' is zero bytes');
69
+ continue;
70
+ }
71
  $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
72
  break;
73
  }
178
  if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
179
 
180
  if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
181
+ $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
182
  }
183
  else {
184
  $info['md5_data_source'] = '';
205
  return true;
206
  }
207
 
 
 
 
 
 
208
 
209
+ /**
210
+ * @param string $BlockData
211
+ *
212
+ * @return array
213
+ */
214
+ public static function parseSTREAMINFOdata($BlockData) {
215
+ $streaminfo = array();
216
  $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
217
  $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
218
  $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
224
  $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1;
225
  $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
226
 
227
+ $streaminfo['audio_signature'] = substr($BlockData, 18, 16);
228
+
229
+ return $streaminfo;
230
+ }
231
+
232
+ /**
233
+ * @param string $BlockData
234
+ *
235
+ * @return bool
236
+ */
237
+ private function parseSTREAMINFO($BlockData) {
238
+ $info = &$this->getid3->info;
239
 
240
+ $info['flac']['STREAMINFO'] = self::parseSTREAMINFOdata($BlockData);
241
+
242
+ if (!empty($info['flac']['STREAMINFO']['sample_rate'])) {
243
 
244
  $info['audio']['bitrate_mode'] = 'vbr';
245
+ $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate'];
246
+ $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels'];
247
+ $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
248
+ $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate'];
249
  if ($info['playtime_seconds'] > 0) {
250
  if (!$this->isDependencyFor('matroska')) {
251
  $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
262
  return true;
263
  }
264
 
265
+ /**
266
+ * @param string $BlockData
267
+ *
268
+ * @return bool
269
+ */
270
  private function parseAPPLICATION($BlockData) {
271
  $info = &$this->getid3->info;
272
 
277
  return true;
278
  }
279
 
280
+ /**
281
+ * @param string $BlockData
282
+ *
283
+ * @return bool
284
+ */
285
  private function parseSEEKTABLE($BlockData) {
286
  $info = &$this->getid3->info;
287
 
311
  return true;
312
  }
313
 
314
+ /**
315
+ * @param string $BlockData
316
+ *
317
+ * @return bool
318
+ */
319
  private function parseVORBIS_COMMENT($BlockData) {
320
  $info = &$this->getid3->info;
321
 
335
  return true;
336
  }
337
 
338
+ /**
339
+ * @param string $BlockData
340
+ *
341
+ * @return bool
342
+ */
343
  private function parseCUESHEET($BlockData) {
344
  $info = &$this->getid3->info;
345
  $offset = 0;
392
  }
393
 
394
  /**
395
+ * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
396
+ * External usage: audio.ogg
397
+ *
398
+ * @return bool
399
+ */
400
  public function parsePICTURE() {
401
  $info = &$this->getid3->info;
402
 
428
  return true;
429
  }
430
 
431
+ /**
432
+ * @param int $blocktype
433
+ *
434
+ * @return string
435
+ */
436
  public static function metaBlockTypeLookup($blocktype) {
437
  static $lookup = array(
438
  0 => 'STREAMINFO',
446
  return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
447
  }
448
 
449
+ /**
450
+ * @param int $applicationid
451
+ *
452
+ * @return string
453
+ */
454
  public static function applicationIDLookup($applicationid) {
455
  // http://flac.sourceforge.net/id.html
456
  static $lookup = array(
481
  return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
482
  }
483
 
484
+ /**
485
+ * @param int $type_id
486
+ *
487
+ * @return string
488
+ */
489
  public static function pictureTypeLookup($type_id) {
490
  static $lookup = array (
491
  0 => 'Other',
lib/getid3/module.audio.la.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.la.php //
@@ -18,7 +18,9 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
18
 
19
  class getid3_la extends getid3_handler
20
  {
21
-
 
 
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
@@ -42,13 +44,13 @@ class getid3_la extends getid3_handler
42
  $info['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
43
  $offset += 4;
44
  if ($info['la']['uncompressed_size'] == 0) {
45
- $info['error'][] = 'Corrupt LA file: uncompressed_size == zero';
46
  return false;
47
  }
48
 
49
  $WAVEchunk = substr($rawdata, $offset, 4);
50
  if ($WAVEchunk !== 'WAVE') {
51
- $info['error'][] = 'Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.';
52
  return false;
53
  }
54
  $offset += 4;
@@ -69,7 +71,7 @@ class getid3_la extends getid3_handler
69
 
70
  $fmt_chunk = substr($rawdata, $offset, 4);
71
  if ($fmt_chunk !== 'fmt ') {
72
- $info['error'][] = 'Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.';
73
  return false;
74
  }
75
  $offset += 4;
@@ -82,14 +84,14 @@ class getid3_la extends getid3_handler
82
  $info['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
83
  $offset += 2;
84
  if ($info['la']['channels'] == 0) {
85
- $info['error'][] = 'Corrupt LA file: channels == zero';
86
  return false;
87
  }
88
 
89
  $info['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
90
  $offset += 4;
91
  if ($info['la']['sample_rate'] == 0) {
92
- $info['error'][] = 'Corrupt LA file: sample_rate == zero';
93
  return false;
94
  }
95
 
@@ -146,7 +148,7 @@ class getid3_la extends getid3_handler
146
  $offset += 4;
147
 
148
  if ($info['la']['footerstart'] > $info['filesize']) {
149
- $info['warning'][] = 'FooterStart value points to offset '.$info['la']['footerstart'].' which is beyond end-of-file ('.$info['filesize'].')';
150
  $info['la']['footerstart'] = $info['filesize'];
151
  }
152
 
@@ -182,7 +184,7 @@ class getid3_la extends getid3_handler
182
  if (empty($getid3_temp->info['error'])) {
183
  $info['riff'] = $getid3_temp->info['riff'];
184
  } else {
185
- $info['warning'][] = 'Error parsing RIFF portion of La file: '.implode($getid3_temp->info['error']);
186
  }
187
  unset($getid3_temp, $getid3_riff);
188
  }
@@ -197,7 +199,7 @@ class getid3_la extends getid3_handler
197
  $info['la']['compression_ratio'] = (float) (($info['avdataend'] - $info['avdataoffset']) / $info['la']['uncompressed_size']);
198
  $info['playtime_seconds'] = (float) ($info['la']['samples'] / $info['la']['sample_rate']) / $info['la']['channels'];
199
  if ($info['playtime_seconds'] == 0) {
200
- $info['error'][] = 'Corrupt LA file: playtime_seconds == zero';
201
  return false;
202
  }
203
 
@@ -208,9 +210,9 @@ class getid3_la extends getid3_handler
208
 
209
  default:
210
  if (substr($rawdata, $offset, 2) == 'LA') {
211
- $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] does not support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.';
212
  } else {
213
- $info['error'][] = 'Not a LA (Lossless-Audio) file';
214
  }
215
  return false;
216
  break;
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.la.php //
18
 
19
  class getid3_la extends getid3_handler
20
  {
21
+ /**
22
+ * @return bool
23
+ */
24
  public function Analyze() {
25
  $info = &$this->getid3->info;
26
 
44
  $info['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
45
  $offset += 4;
46
  if ($info['la']['uncompressed_size'] == 0) {
47
+ $this->error('Corrupt LA file: uncompressed_size == zero');
48
  return false;
49
  }
50
 
51
  $WAVEchunk = substr($rawdata, $offset, 4);
52
  if ($WAVEchunk !== 'WAVE') {
53
+ $this->error('Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.');
54
  return false;
55
  }
56
  $offset += 4;
71
 
72
  $fmt_chunk = substr($rawdata, $offset, 4);
73
  if ($fmt_chunk !== 'fmt ') {
74
+ $this->error('Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.');
75
  return false;
76
  }
77
  $offset += 4;
84
  $info['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
85
  $offset += 2;
86
  if ($info['la']['channels'] == 0) {
87
+ $this->error('Corrupt LA file: channels == zero');
88
  return false;
89
  }
90
 
91
  $info['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
92
  $offset += 4;
93
  if ($info['la']['sample_rate'] == 0) {
94
+ $this->error('Corrupt LA file: sample_rate == zero');
95
  return false;
96
  }
97
 
148
  $offset += 4;
149
 
150
  if ($info['la']['footerstart'] > $info['filesize']) {
151
+ $this->warning('FooterStart value points to offset '.$info['la']['footerstart'].' which is beyond end-of-file ('.$info['filesize'].')');
152
  $info['la']['footerstart'] = $info['filesize'];
153
  }
154
 
184
  if (empty($getid3_temp->info['error'])) {
185
  $info['riff'] = $getid3_temp->info['riff'];
186
  } else {
187
+ $this->warning('Error parsing RIFF portion of La file: '.implode($getid3_temp->info['error']));
188
  }
189
  unset($getid3_temp, $getid3_riff);
190
  }
199
  $info['la']['compression_ratio'] = (float) (($info['avdataend'] - $info['avdataoffset']) / $info['la']['uncompressed_size']);
200
  $info['playtime_seconds'] = (float) ($info['la']['samples'] / $info['la']['sample_rate']) / $info['la']['channels'];
201
  if ($info['playtime_seconds'] == 0) {
202
+ $this->error('Corrupt LA file: playtime_seconds == zero');
203
  return false;
204
  }
205
 
210
 
211
  default:
212
  if (substr($rawdata, $offset, 2) == 'LA') {
213
+ $this->error('This version of getID3() ['.$this->getid3->version().'] does not support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.');
214
  } else {
215
+ $this->error('Not a LA (Lossless-Audio) file');
216
  }
217
  return false;
218
  break;
lib/getid3/module.audio.lpac.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.lpac.php //
@@ -18,14 +18,17 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
18
 
19
  class getid3_lpac extends getid3_handler
20
  {
21
-
 
 
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
25
  $this->fseek($info['avdataoffset']);
26
  $LPACheader = $this->fread(14);
27
- if (substr($LPACheader, 0, 4) != 'LPAC') {
28
- $info['error'][] = 'Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"';
 
29
  return false;
30
  }
31
  $info['avdataoffset'] += 14;
@@ -46,7 +49,7 @@ class getid3_lpac extends getid3_handler
46
  $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01);
47
 
48
  if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) {
49
- $info['warning'][] = '24-bit and 16-bit flags cannot both be set';
50
  }
51
 
52
  $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
@@ -59,20 +62,20 @@ class getid3_lpac extends getid3_handler
59
  $info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F);
60
 
61
  if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) {
62
- $info['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"';
63
  }
64
  switch ($info['lpac']['file_version']) {
65
  case 6:
66
  if ($info['lpac']['flags']['adaptive_quantization']) {
67
- $info['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true';
68
  }
69
  if ($info['lpac']['quantization'] != 20) {
70
- $info['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q'];
71
  }
72
  break;
73
 
74
  default:
75
- //$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org';
76
  break;
77
  }
78
 
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.lpac.php //
18
 
19
  class getid3_lpac extends getid3_handler
20
  {
21
+ /**
22
+ * @return bool
23
+ */
24
  public function Analyze() {
25
  $info = &$this->getid3->info;
26
 
27
  $this->fseek($info['avdataoffset']);
28
  $LPACheader = $this->fread(14);
29
+ $StreamMarker = substr($LPACheader, 0, 4);
30
+ if ($StreamMarker != 'LPAC') {
31
+ $this->error('Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"');
32
  return false;
33
  }
34
  $info['avdataoffset'] += 14;
49
  $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01);
50
 
51
  if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) {
52
+ $this->warning('24-bit and 16-bit flags cannot both be set');
53
  }
54
 
55
  $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
62
  $info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F);
63
 
64
  if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) {
65
+ $this->warning('max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"');
66
  }
67
  switch ($info['lpac']['file_version']) {
68
  case 6:
69
  if ($info['lpac']['flags']['adaptive_quantization']) {
70
+ $this->warning('adaptive_quantization expected to be false in LPAC file stucture v6, actually true');
71
  }
72
  if ($info['lpac']['quantization'] != 20) {
73
+ $this->warning('Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q']);
74
  }
75
  break;
76
 
77
  default:
78
+ //$this->warning('This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org');
79
  break;
80
  }
81
 
lib/getid3/module.audio.midi.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.midi.php //
@@ -19,8 +19,14 @@ define('GETID3_MIDI_MAGIC_MTRK', 'MTrk'); // MIDI track header magic
19
 
20
  class getid3_midi extends getid3_handler
21
  {
 
 
 
22
  public $scanwholefile = true;
23
 
 
 
 
24
  public function Analyze() {
25
  $info = &$this->getid3->info;
26
 
@@ -37,7 +43,7 @@ class getid3_midi extends getid3_handler
37
  $offset = 0;
38
  $MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd'
39
  if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) {
40
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"';
41
  unset($info['fileformat']);
42
  return false;
43
  }
@@ -56,8 +62,8 @@ class getid3_midi extends getid3_handler
56
  if ($buffer = $this->fread($this->getid3->fread_buffer_size())) {
57
  $MIDIdata .= $buffer;
58
  } else {
59
- $info['warning'][] = 'only processed '.($i - 1).' of '.$thisfile_midi_raw['tracks'].' tracks';
60
- $info['error'][] = 'Unabled to read more file data at '.$this->ftell().' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes';
61
  return false;
62
  }
63
  }
@@ -70,13 +76,13 @@ class getid3_midi extends getid3_handler
70
  $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
71
  $offset += $tracksize;
72
  } else {
73
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset - 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead';
74
  return false;
75
  }
76
  }
77
 
78
  if (!isset($trackdataarray) || !is_array($trackdataarray)) {
79
- $info['error'][] = 'Cannot find MIDI track information';
80
  unset($thisfile_midi);
81
  unset($info['fileformat']);
82
  return false;
@@ -88,6 +94,7 @@ class getid3_midi extends getid3_handler
88
  $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
89
  $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
90
  $MicroSecondsPerQuarterNoteAfter = array ();
 
91
 
92
  foreach ($trackdataarray as $tracknumber => $trackdata) {
93
 
@@ -226,7 +233,7 @@ class getid3_midi extends getid3_handler
226
  case 0x51: // Tempo: microseconds / quarter note
227
  $CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
228
  if ($CurrentMicroSecondsPerBeat == 0) {
229
- $info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
230
  return false;
231
  }
232
  $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
@@ -269,13 +276,13 @@ class getid3_midi extends getid3_handler
269
  break;
270
 
271
  default:
272
- $info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;
273
  break;
274
  }
275
 
276
  } else {
277
 
278
- $info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel'];
279
 
280
  }
281
  }
@@ -283,7 +290,8 @@ class getid3_midi extends getid3_handler
283
  $thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
284
  }
285
  }
286
- $previoustickoffset = null;
 
287
 
288
  ksort($MicroSecondsPerQuarterNoteAfter);
289
  foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
@@ -295,7 +303,7 @@ class getid3_midi extends getid3_handler
295
  if ($thisfile_midi['totalticks'] > $tickoffset) {
296
 
297
  if ($thisfile_midi_raw['ticksperqnote'] == 0) {
298
- $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
299
  return false;
300
  }
301
 
@@ -308,11 +316,11 @@ class getid3_midi extends getid3_handler
308
  if ($thisfile_midi['totalticks'] > $previoustickoffset) {
309
 
310
  if ($thisfile_midi_raw['ticksperqnote'] == 0) {
311
- $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
312
  return false;
313
  }
314
 
315
- $info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000);
316
 
317
  }
318
  }
@@ -329,6 +337,11 @@ class getid3_midi extends getid3_handler
329
  return true;
330
  }
331
 
 
 
 
 
 
332
  public function GeneralMIDIinstrumentLookup($instrumentid) {
333
 
334
  $begin = __LINE__;
@@ -469,6 +482,11 @@ class getid3_midi extends getid3_handler
469
  return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');
470
  }
471
 
 
 
 
 
 
472
  public function GeneralMIDIpercussionLookup($instrumentid) {
473
 
474
  $begin = __LINE__;
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.midi.php //
19
 
20
  class getid3_midi extends getid3_handler
21
  {
22
+ /**
23
+ * @var bool
24
+ */
25
  public $scanwholefile = true;
26
 
27
+ /**
28
+ * @return bool
29
+ */
30
  public function Analyze() {
31
  $info = &$this->getid3->info;
32
 
43
  $offset = 0;
44
  $MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd'
45
  if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) {
46
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"');
47
  unset($info['fileformat']);
48
  return false;
49
  }
62
  if ($buffer = $this->fread($this->getid3->fread_buffer_size())) {
63
  $MIDIdata .= $buffer;
64
  } else {
65
+ $this->warning('only processed '.($i - 1).' of '.$thisfile_midi_raw['tracks'].' tracks');
66
+ $this->error('Unabled to read more file data at '.$this->ftell().' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes');
67
  return false;
68
  }
69
  }
76
  $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
77
  $offset += $tracksize;
78
  } else {
79
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset - 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead');
80
  return false;
81
  }
82
  }
83
 
84
  if (!isset($trackdataarray) || !is_array($trackdataarray)) {
85
+ $this->error('Cannot find MIDI track information');
86
  unset($thisfile_midi);
87
  unset($info['fileformat']);
88
  return false;
94
  $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
95
  $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
96
  $MicroSecondsPerQuarterNoteAfter = array ();
97
+ $MIDIevents = array();
98
 
99
  foreach ($trackdataarray as $tracknumber => $trackdata) {
100
 
233
  case 0x51: // Tempo: microseconds / quarter note
234
  $CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
235
  if ($CurrentMicroSecondsPerBeat == 0) {
236
+ $this->error('Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero');
237
  return false;
238
  }
239
  $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
276
  break;
277
 
278
  default:
279
+ $this->warning('Unhandled META Event Command: '.$METAeventCommand);
280
  break;
281
  }
282
 
283
  } else {
284
 
285
+ $this->warning('Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel']);
286
 
287
  }
288
  }
290
  $thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
291
  }
292
  }
293
+ $previoustickoffset = null;
294
+ $prevmicrosecondsperbeat = null;
295
 
296
  ksort($MicroSecondsPerQuarterNoteAfter);
297
  foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
303
  if ($thisfile_midi['totalticks'] > $tickoffset) {
304
 
305
  if ($thisfile_midi_raw['ticksperqnote'] == 0) {
306
+ $this->error('Corrupt MIDI file: ticksperqnote == zero');
307
  return false;
308
  }
309
 
316
  if ($thisfile_midi['totalticks'] > $previoustickoffset) {
317
 
318
  if ($thisfile_midi_raw['ticksperqnote'] == 0) {
319
+ $this->error('Corrupt MIDI file: ticksperqnote == zero');
320
  return false;
321
  }
322
 
323
+ $info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000);
324
 
325
  }
326
  }
337
  return true;
338
  }
339
 
340
+ /**
341
+ * @param int $instrumentid
342
+ *
343
+ * @return string
344
+ */
345
  public function GeneralMIDIinstrumentLookup($instrumentid) {
346
 
347
  $begin = __LINE__;
482
  return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');
483
  }
484
 
485
+ /**
486
+ * @param int $instrumentid
487
+ *
488
+ * @return string
489
+ */
490
  public function GeneralMIDIpercussionLookup($instrumentid) {
491
 
492
  $begin = __LINE__;
lib/getid3/module.audio.mod.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.mod.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_mod extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
  $this->fseek($info['avdataoffset']);
@@ -31,68 +33,79 @@ class getid3_mod extends getid3_handler
31
  } elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) {
32
  return $this->getMODheaderFilepointer();
33
  }
34
- $info['error'][] = 'This is not a known type of MOD file';
35
  return false;
36
  }
37
 
38
-
 
 
39
  public function getMODheaderFilepointer() {
40
  $info = &$this->getid3->info;
41
  $this->fseek($info['avdataoffset'] + 1080);
42
  $FormatID = $this->fread(4);
43
  if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
44
- $info['error'][] = 'This is not a known type of MOD file';
45
  return false;
46
  }
47
 
48
  $info['fileformat'] = 'mod';
49
 
50
- $info['error'][] = 'MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
51
  return false;
52
  }
53
 
 
 
 
54
  public function getXMheaderFilepointer() {
55
  $info = &$this->getid3->info;
56
  $this->fseek($info['avdataoffset']);
57
  $FormatID = $this->fread(15);
58
  if (!preg_match('#^Extended Module$#', $FormatID)) {
59
- $info['error'][] = 'This is not a known type of XM-MOD file';
60
  return false;
61
  }
62
 
63
  $info['fileformat'] = 'xm';
64
 
65
- $info['error'][] = 'XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
66
  return false;
67
  }
68
 
 
 
 
69
  public function getS3MheaderFilepointer() {
70
  $info = &$this->getid3->info;
71
  $this->fseek($info['avdataoffset'] + 44);
72
  $FormatID = $this->fread(4);
73
  if (!preg_match('#^SCRM$#', $FormatID)) {
74
- $info['error'][] = 'This is not a ScreamTracker MOD file';
75
  return false;
76
  }
77
 
78
  $info['fileformat'] = 's3m';
79
 
80
- $info['error'][] = 'ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
81
  return false;
82
  }
83
 
 
 
 
84
  public function getITheaderFilepointer() {
85
  $info = &$this->getid3->info;
86
  $this->fseek($info['avdataoffset']);
87
  $FormatID = $this->fread(4);
88
  if (!preg_match('#^IMPM$#', $FormatID)) {
89
- $info['error'][] = 'This is not an ImpulseTracker MOD file';
90
  return false;
91
  }
92
 
93
  $info['fileformat'] = 'it';
94
 
95
- $info['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
96
  return false;
97
  }
98
 
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.mod.php //
17
 
18
  class getid3_mod extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
  $this->fseek($info['avdataoffset']);
33
  } elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) {
34
  return $this->getMODheaderFilepointer();
35
  }
36
+ $this->error('This is not a known type of MOD file');
37
  return false;
38
  }
39
 
40
+ /**
41
+ * @return bool
42
+ */
43
  public function getMODheaderFilepointer() {
44
  $info = &$this->getid3->info;
45
  $this->fseek($info['avdataoffset'] + 1080);
46
  $FormatID = $this->fread(4);
47
  if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
48
+ $this->error('This is not a known type of MOD file');
49
  return false;
50
  }
51
 
52
  $info['fileformat'] = 'mod';
53
 
54
+ $this->error('MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
55
  return false;
56
  }
57
 
58
+ /**
59
+ * @return bool
60
+ */
61
  public function getXMheaderFilepointer() {
62
  $info = &$this->getid3->info;
63
  $this->fseek($info['avdataoffset']);
64
  $FormatID = $this->fread(15);
65
  if (!preg_match('#^Extended Module$#', $FormatID)) {
66
+ $this->error('This is not a known type of XM-MOD file');
67
  return false;
68
  }
69
 
70
  $info['fileformat'] = 'xm';
71
 
72
+ $this->error('XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
73
  return false;
74
  }
75
 
76
+ /**
77
+ * @return bool
78
+ */
79
  public function getS3MheaderFilepointer() {
80
  $info = &$this->getid3->info;
81
  $this->fseek($info['avdataoffset'] + 44);
82
  $FormatID = $this->fread(4);
83
  if (!preg_match('#^SCRM$#', $FormatID)) {
84
+ $this->error('This is not a ScreamTracker MOD file');
85
  return false;
86
  }
87
 
88
  $info['fileformat'] = 's3m';
89
 
90
+ $this->error('ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
91
  return false;
92
  }
93
 
94
+ /**
95
+ * @return bool
96
+ */
97
  public function getITheaderFilepointer() {
98
  $info = &$this->getid3->info;
99
  $this->fseek($info['avdataoffset']);
100
  $FormatID = $this->fread(4);
101
  if (!preg_match('#^IMPM$#', $FormatID)) {
102
+ $this->error('This is not an ImpulseTracker MOD file');
103
  return false;
104
  }
105
 
106
  $info['fileformat'] = 'it';
107
 
108
+ $this->error('ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
109
  return false;
110
  }
111
 
lib/getid3/module.audio.monkey.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.monkey.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_monkey extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -39,7 +41,7 @@ class getid3_monkey extends getid3_handler
39
  $thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4);
40
  $magic = 'MAC ';
41
  if ($thisfile_monkeysaudio_raw['magic'] != $magic) {
42
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_monkeysaudio_raw['magic']).'"';
43
  unset($info['fileformat']);
44
  return false;
45
  }
@@ -112,7 +114,7 @@ class getid3_monkey extends getid3_handler
112
  $info['audio']['channels'] = $thisfile_monkeysaudio['channels'];
113
  $thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate'];
114
  if ($thisfile_monkeysaudio['sample_rate'] == 0) {
115
- $info['error'][] = 'Corrupt MAC file: frequency == zero';
116
  return false;
117
  }
118
  $info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate'];
@@ -127,14 +129,14 @@ class getid3_monkey extends getid3_handler
127
  }
128
  $thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
129
  if ($thisfile_monkeysaudio['playtime'] == 0) {
130
- $info['error'][] = 'Corrupt MAC file: playtime == zero';
131
  return false;
132
  }
133
  $info['playtime_seconds'] = $thisfile_monkeysaudio['playtime'];
134
  $thisfile_monkeysaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset'];
135
  $thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8);
136
  if ($thisfile_monkeysaudio['uncompressed_size'] == 0) {
137
- $info['error'][] = 'Corrupt MAC file: uncompressed_size == zero';
138
  return false;
139
  }
140
  $thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']);
@@ -155,7 +157,7 @@ class getid3_monkey extends getid3_handler
155
 
156
  if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
157
  if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) {
158
- //$info['warning'][] = 'cFileMD5 is null';
159
  } else {
160
  $info['md5_data_source'] = '';
161
  $md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
@@ -177,6 +179,11 @@ class getid3_monkey extends getid3_handler
177
  return true;
178
  }
179
 
 
 
 
 
 
180
  public function MonkeyCompressionLevelNameLookup($compressionlevel) {
181
  static $MonkeyCompressionLevelNameLookup = array(
182
  0 => 'unknown',
@@ -189,6 +196,12 @@ class getid3_monkey extends getid3_handler
189
  return (isset($MonkeyCompressionLevelNameLookup[$compressionlevel]) ? $MonkeyCompressionLevelNameLookup[$compressionlevel] : 'invalid');
190
  }
191
 
 
 
 
 
 
 
192
  public function MonkeySamplesPerFrame($versionid, $compressionlevel) {
193
  if ($versionid >= 3950) {
194
  return 73728 * 4;
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.monkey.php //
17
 
18
  class getid3_monkey extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
41
  $thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4);
42
  $magic = 'MAC ';
43
  if ($thisfile_monkeysaudio_raw['magic'] != $magic) {
44
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_monkeysaudio_raw['magic']).'"');
45
  unset($info['fileformat']);
46
  return false;
47
  }
114
  $info['audio']['channels'] = $thisfile_monkeysaudio['channels'];
115
  $thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate'];
116
  if ($thisfile_monkeysaudio['sample_rate'] == 0) {
117
+ $this->error('Corrupt MAC file: frequency == zero');
118
  return false;
119
  }
120
  $info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate'];
129
  }
130
  $thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
131
  if ($thisfile_monkeysaudio['playtime'] == 0) {
132
+ $this->error('Corrupt MAC file: playtime == zero');
133
  return false;
134
  }
135
  $info['playtime_seconds'] = $thisfile_monkeysaudio['playtime'];
136
  $thisfile_monkeysaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset'];
137
  $thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8);
138
  if ($thisfile_monkeysaudio['uncompressed_size'] == 0) {
139
+ $this->error('Corrupt MAC file: uncompressed_size == zero');
140
  return false;
141
  }
142
  $thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']);
157
 
158
  if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
159
  if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) {
160
+ //$this->warning('cFileMD5 is null');
161
  } else {
162
  $info['md5_data_source'] = '';
163
  $md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
179
  return true;
180
  }
181
 
182
+ /**
183
+ * @param int $compressionlevel
184
+ *
185
+ * @return string
186
+ */
187
  public function MonkeyCompressionLevelNameLookup($compressionlevel) {
188
  static $MonkeyCompressionLevelNameLookup = array(
189
  0 => 'unknown',
196
  return (isset($MonkeyCompressionLevelNameLookup[$compressionlevel]) ? $MonkeyCompressionLevelNameLookup[$compressionlevel] : 'invalid');
197
  }
198
 
199
+ /**
200
+ * @param int $versionid
201
+ * @param int $compressionlevel
202
+ *
203
+ * @return int
204
+ */
205
  public function MonkeySamplesPerFrame($versionid, $compressionlevel) {
206
  if ($versionid >= 3950) {
207
  return 73728 * 4;
lib/getid3/module.audio.mp3.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.mp3.php //
@@ -24,9 +24,17 @@ define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
24
 
25
  class getid3_mp3 extends getid3_handler
26
  {
27
-
28
- public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files
29
-
 
 
 
 
 
 
 
 
30
  public function Analyze() {
31
  $info = &$this->getid3->info;
32
 
@@ -34,8 +42,8 @@ class getid3_mp3 extends getid3_handler
34
 
35
  if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
36
  if ($this->allow_bruteforce) {
37
- $info['error'][] = 'Rescanning file in BruteForce mode';
38
- $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info);
39
  }
40
  }
41
 
@@ -72,7 +80,7 @@ class getid3_mp3 extends getid3_handler
72
  }
73
 
74
  }
75
- $info['warning'][] = $synchoffsetwarning;
76
 
77
  }
78
 
@@ -134,7 +142,7 @@ class getid3_mp3 extends getid3_handler
134
  break;
135
 
136
  default:
137
- $info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"';
138
  break;
139
  }
140
  }
@@ -152,7 +160,11 @@ class getid3_mp3 extends getid3_handler
152
 
153
  // Calculate playtime
154
  if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
155
- $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
 
 
 
 
156
  }
157
 
158
  $info['audio']['encoder_options'] = $this->GuessEncoderOptions();
@@ -160,10 +172,14 @@ class getid3_mp3 extends getid3_handler
160
  return true;
161
  }
162
 
163
-
 
 
164
  public function GuessEncoderOptions() {
165
  // shortcuts
166
  $info = &$this->getid3->info;
 
 
167
  if (!empty($info['mpeg']['audio'])) {
168
  $thisfile_mpeg_audio = &$info['mpeg']['audio'];
169
  if (!empty($thisfile_mpeg_audio['LAME'])) {
@@ -178,7 +194,7 @@ class getid3_mp3 extends getid3_handler
178
 
179
  $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
180
 
181
- } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
182
 
183
  $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
184
 
@@ -404,7 +420,15 @@ class getid3_mp3 extends getid3_handler
404
  return $encoder_options;
405
  }
406
 
407
-
 
 
 
 
 
 
 
 
408
  public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
409
  static $MPEGaudioVersionLookup;
410
  static $MPEGaudioLayerLookup;
@@ -424,7 +448,7 @@ class getid3_mp3 extends getid3_handler
424
  }
425
 
426
  if ($this->fseek($offset) != 0) {
427
- $info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
428
  return false;
429
  }
430
  //$headerstring = $this->fread(1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
@@ -437,18 +461,19 @@ class getid3_mp3 extends getid3_handler
437
  // and $cc... is the audio data
438
 
439
  $head4 = substr($headerstring, 0, 4);
 
440
  static $MPEGaudioHeaderDecodeCache = array();
441
- if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
442
- $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
443
  } else {
444
  $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4);
445
- $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
446
  }
447
 
448
  static $MPEGaudioHeaderValidCache = array();
449
- if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache
450
- //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)
451
- $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);
452
  }
453
 
454
  // shortcut
@@ -457,11 +482,10 @@ class getid3_mp3 extends getid3_handler
457
  }
458
  $thisfile_mpeg_audio = &$info['mpeg']['audio'];
459
 
460
-
461
- if ($MPEGaudioHeaderValidCache[$head4]) {
462
  $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
463
  } else {
464
- $info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset;
465
  return false;
466
  }
467
 
@@ -489,7 +513,7 @@ class getid3_mp3 extends getid3_handler
489
 
490
  if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
491
  // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
492
- $info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
493
  $thisfile_mpeg_audio['raw']['bitrate'] = 0;
494
  }
495
  $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
@@ -511,7 +535,7 @@ class getid3_mp3 extends getid3_handler
511
  if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
512
  // these are ok
513
  } else {
514
- $info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
515
  return false;
516
  }
517
  break;
@@ -522,7 +546,7 @@ class getid3_mp3 extends getid3_handler
522
  if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
523
  // these are ok
524
  } else {
525
- $info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
526
  return false;
527
  }
528
  break;
@@ -544,7 +568,7 @@ class getid3_mp3 extends getid3_handler
544
  if (isset($thisfile_mpeg_audio['framelength'])) {
545
  $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength'];
546
  } else {
547
- $info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.';
548
  return false;
549
  }
550
 
@@ -561,7 +585,7 @@ class getid3_mp3 extends getid3_handler
561
 
562
  $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
563
  $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer';
564
- $info['audio']['codec'] = 'Fraunhofer';
565
 
566
  $SideInfoData = substr($headerstring, 4 + 2, 32);
567
 
@@ -654,10 +678,10 @@ class getid3_mp3 extends getid3_handler
654
  $used_filesize = $thisfile_mpeg_audio['VBR_bytes'];
655
  } elseif (!empty($info['filesize'])) {
656
  $used_filesize = $info['filesize'];
657
- $used_filesize -= intval(@$info['id3v2']['headerlength']);
658
  $used_filesize -= (isset($info['id3v1']) ? 128 : 0);
659
  $used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0);
660
- $info['warning'][] = 'MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes';
661
  }
662
 
663
  $framelengthfloat = $used_filesize / $thisfile_mpeg_audio['VBR_frames'];
@@ -847,7 +871,7 @@ class getid3_mp3 extends getid3_handler
847
  $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
848
  $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
849
  if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
850
- $info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org';
851
  }
852
  if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
853
  // this may change if 3.90.4 ever comes out
@@ -891,7 +915,7 @@ class getid3_mp3 extends getid3_handler
891
  $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
892
  }
893
  if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
894
- $info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
895
  }
896
  }
897
 
@@ -918,12 +942,12 @@ class getid3_mp3 extends getid3_handler
918
  // $this->fseek($prenullbytefileoffset);
919
  // if ($PossibleNullByte === "\x00") {
920
  $info['avdataend']--;
921
- // $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
922
  // } else {
923
- // $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
924
  // }
925
  } else {
926
- $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
927
  }
928
  }
929
  }
@@ -941,7 +965,7 @@ class getid3_mp3 extends getid3_handler
941
  $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
942
  }
943
  } else {
944
- $info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header';
945
  }
946
  }
947
  }
@@ -1082,9 +1106,16 @@ class getid3_mp3 extends getid3_handler
1082
  return true;
1083
  }
1084
 
 
 
 
 
 
 
 
1085
  public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
1086
  $info = &$this->getid3->info;
1087
- $firstframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1088
  $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
1089
 
1090
  for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
@@ -1094,7 +1125,7 @@ class getid3_mp3 extends getid3_handler
1094
  return true;
1095
  }
1096
 
1097
- $nextframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1098
  if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
1099
  if ($ScanAsCBR) {
1100
  // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
@@ -1108,7 +1139,7 @@ class getid3_mp3 extends getid3_handler
1108
  if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) {
1109
  $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
1110
  } else {
1111
- $info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.';
1112
  return false;
1113
  }
1114
 
@@ -1120,7 +1151,7 @@ class getid3_mp3 extends getid3_handler
1120
  } else {
1121
 
1122
  // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
1123
- $info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.';
1124
 
1125
  return false;
1126
  }
@@ -1128,6 +1159,12 @@ class getid3_mp3 extends getid3_handler
1128
  return true;
1129
  }
1130
 
 
 
 
 
 
 
1131
  public function FreeFormatFrameLength($offset, $deepscan=false) {
1132
  $info = &$this->getid3->info;
1133
 
@@ -1163,10 +1200,10 @@ class getid3_mp3 extends getid3_handler
1163
  $framelength = $framelength2;
1164
  }
1165
  if (!$framelength) {
1166
- $info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset;
1167
  return false;
1168
  } else {
1169
- $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';
1170
  $info['audio']['codec'] = 'LAME';
1171
  $info['audio']['encoder'] = 'LAME3.88';
1172
  $SyncPattern1 = substr($SyncPattern1, 0, 3);
@@ -1193,7 +1230,7 @@ class getid3_mp3 extends getid3_handler
1193
  $ActualFrameLengthValues[] = ($framelength + 1);
1194
  $nextoffset++;
1195
  } else {
1196
- $info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset;
1197
  return false;
1198
  }
1199
  $nextoffset += $framelength;
@@ -1205,6 +1242,9 @@ class getid3_mp3 extends getid3_handler
1205
  return $framelength;
1206
  }
1207
 
 
 
 
1208
  public function getOnlyMPEGaudioInfoBruteForce() {
1209
  $MPEGaudioHeaderDecodeCache = array();
1210
  $MPEGaudioHeaderValidCache = array();
@@ -1291,7 +1331,7 @@ class getid3_mp3 extends getid3_handler
1291
  getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
1292
  if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
1293
  $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
1294
- $info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
1295
  foreach ($Distribution as $key1 => $value1) {
1296
  foreach ($value1 as $key2 => $value2) {
1297
  $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
@@ -1318,13 +1358,13 @@ class getid3_mp3 extends getid3_handler
1318
  $info['mpeg']['audio']['version_distribution'] = $Distribution['version'];
1319
  $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding'];
1320
  if (count($Distribution['version']) > 1) {
1321
- $info['error'][] = 'Corrupt file - more than one MPEG version detected';
1322
  }
1323
  if (count($Distribution['layer']) > 1) {
1324
- $info['error'][] = 'Corrupt file - more than one MPEG layer detected';
1325
  }
1326
  if (count($Distribution['frequency']) > 1) {
1327
- $info['error'][] = 'Corrupt file - more than one MPEG sample rate detected';
1328
  }
1329
 
1330
 
@@ -1336,7 +1376,7 @@ class getid3_mp3 extends getid3_handler
1336
  }
1337
  $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']);
1338
  if ($info['mpeg']['audio']['frame_count'] == 0) {
1339
- $info['error'][] = 'no MPEG audio frames found';
1340
  return false;
1341
  }
1342
  $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']);
@@ -1352,7 +1392,12 @@ class getid3_mp3 extends getid3_handler
1352
  return true;
1353
  }
1354
 
1355
-
 
 
 
 
 
1356
  public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) {
1357
  // looks for synch, decodes MPEG audio header
1358
 
@@ -1362,16 +1407,15 @@ class getid3_mp3 extends getid3_handler
1362
  static $MPEGaudioLayerLookup;
1363
  static $MPEGaudioBitrateLookup;
1364
  if (empty($MPEGaudioVersionLookup)) {
1365
- $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
1366
- $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
1367
- $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
1368
-
1369
  }
1370
 
1371
  $this->fseek($avdataoffset);
1372
  $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
1373
  if ($sync_seek_buffer_size <= 0) {
1374
- $info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
1375
  return false;
1376
  }
1377
  $header = $this->fread($sync_seek_buffer_size);
@@ -1382,7 +1426,7 @@ class getid3_mp3 extends getid3_handler
1382
 
1383
  if ($SynchSeekOffset > $sync_seek_buffer_size) {
1384
  // if a synch's not found within the first 128k bytes, then give up
1385
- $info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB';
1386
  if (isset($info['audio']['bitrate'])) {
1387
  unset($info['audio']['bitrate']);
1388
  }
@@ -1396,7 +1440,7 @@ class getid3_mp3 extends getid3_handler
1396
 
1397
  } elseif (feof($this->getid3->fp)) {
1398
 
1399
- $info['error'][] = 'Could not find valid MPEG audio synch before end of file';
1400
  if (isset($info['audio']['bitrate'])) {
1401
  unset($info['audio']['bitrate']);
1402
  }
@@ -1411,11 +1455,12 @@ class getid3_mp3 extends getid3_handler
1411
  }
1412
 
1413
  if (($SynchSeekOffset + 1) >= strlen($header)) {
1414
- $info['error'][] = 'Could not find valid MPEG synch before end of file';
1415
  return false;
1416
  }
1417
 
1418
  if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
 
1419
  if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
1420
  $FirstFrameThisfileInfo = $info;
1421
  $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
@@ -1439,7 +1484,7 @@ class getid3_mp3 extends getid3_handler
1439
  $info['audio']['dataformat'] = 'mp3';
1440
  break;
1441
  }
1442
- if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
1443
  if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
1444
  // If there is garbage data between a valid VBR header frame and a sequence
1445
  // of valid MPEG-audio frames the VBR data is no longer discarded.
@@ -1454,9 +1499,9 @@ class getid3_mp3 extends getid3_handler
1454
  if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
1455
  $info = $dummy;
1456
  $info['avdataoffset'] = $GarbageOffsetEnd;
1457
- $info['warning'][] = 'apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd;
1458
  } else {
1459
- $info['warning'][] = 'using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')';
1460
  }
1461
  }
1462
  }
@@ -1521,7 +1566,7 @@ class getid3_mp3 extends getid3_handler
1521
  }
1522
  }
1523
  $synchstartoffset = $scan_start_offset[$current_segment];
1524
- while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
1525
  $FastMode = true;
1526
  $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
1527
 
@@ -1549,7 +1594,7 @@ class getid3_mp3 extends getid3_handler
1549
  }
1550
  }
1551
  if ($pct_data_scanned > 0) {
1552
- $info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
1553
  foreach ($info['mpeg']['audio'] as $key1 => $value1) {
1554
  if (!preg_match('#_distribution$#i', $key1)) {
1555
  continue;
@@ -1561,7 +1606,7 @@ class getid3_mp3 extends getid3_handler
1561
  }
1562
 
1563
  if ($SynchErrorsFound > 0) {
1564
- $info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis';
1565
  //return false;
1566
  }
1567
 
@@ -1574,7 +1619,7 @@ class getid3_mp3 extends getid3_handler
1574
  }
1575
  }
1576
  if ($framecounter == 0) {
1577
- $info['error'][] = 'Corrupt MP3 file: framecounter == zero';
1578
  return false;
1579
  }
1580
  $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter);
@@ -1609,7 +1654,7 @@ class getid3_mp3 extends getid3_handler
1609
 
1610
  if (empty($info['mpeg']['audio'])) {
1611
 
1612
- $info['error'][] = 'could not find valid MPEG synch before end of file';
1613
  if (isset($info['audio']['bitrate'])) {
1614
  unset($info['audio']['bitrate']);
1615
  }
@@ -1632,17 +1677,25 @@ class getid3_mp3 extends getid3_handler
1632
  return true;
1633
  }
1634
 
1635
-
 
 
1636
  public static function MPEGaudioVersionArray() {
1637
  static $MPEGaudioVersion = array('2.5', false, '2', '1');
1638
  return $MPEGaudioVersion;
1639
  }
1640
 
 
 
 
1641
  public static function MPEGaudioLayerArray() {
1642
  static $MPEGaudioLayer = array(false, 3, 2, 1);
1643
  return $MPEGaudioLayer;
1644
  }
1645
 
 
 
 
1646
  public static function MPEGaudioBitrateArray() {
1647
  static $MPEGaudioBitrate;
1648
  if (empty($MPEGaudioBitrate)) {
@@ -1662,6 +1715,9 @@ class getid3_mp3 extends getid3_handler
1662
  return $MPEGaudioBitrate;
1663
  }
1664
 
 
 
 
1665
  public static function MPEGaudioFrequencyArray() {
1666
  static $MPEGaudioFrequency;
1667
  if (empty($MPEGaudioFrequency)) {
@@ -1674,11 +1730,17 @@ class getid3_mp3 extends getid3_handler
1674
  return $MPEGaudioFrequency;
1675
  }
1676
 
 
 
 
1677
  public static function MPEGaudioChannelModeArray() {
1678
  static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
1679
  return $MPEGaudioChannelMode;
1680
  }
1681
 
 
 
 
1682
  public static function MPEGaudioModeExtensionArray() {
1683
  static $MPEGaudioModeExtension;
1684
  if (empty($MPEGaudioModeExtension)) {
@@ -1691,15 +1753,31 @@ class getid3_mp3 extends getid3_handler
1691
  return $MPEGaudioModeExtension;
1692
  }
1693
 
 
 
 
1694
  public static function MPEGaudioEmphasisArray() {
1695
  static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
1696
  return $MPEGaudioEmphasis;
1697
  }
1698
 
 
 
 
 
 
 
1699
  public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) {
1700
  return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
1701
  }
1702
 
 
 
 
 
 
 
 
1703
  public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
1704
  if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
1705
  return false;
@@ -1772,6 +1850,11 @@ class getid3_mp3 extends getid3_handler
1772
  return true;
1773
  }
1774
 
 
 
 
 
 
1775
  public static function MPEGaudioHeaderDecode($Header4Bytes) {
1776
  // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
1777
  // A - Frame sync (all bits set)
@@ -1809,6 +1892,15 @@ class getid3_mp3 extends getid3_handler
1809
  return $MPEGrawHeader;
1810
  }
1811
 
 
 
 
 
 
 
 
 
 
1812
  public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) {
1813
  static $AudioFrameLengthCache = array();
1814
 
@@ -1870,6 +1962,11 @@ class getid3_mp3 extends getid3_handler
1870
  return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
1871
  }
1872
 
 
 
 
 
 
1873
  public static function ClosestStandardMP3Bitrate($bit_rate) {
1874
  static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
1875
  static $bit_rate_table = array (0=>'-');
@@ -1890,10 +1987,16 @@ class getid3_mp3 extends getid3_handler
1890
  return $bit_rate_table[$round_bit_rate];
1891
  }
1892
 
 
 
 
 
 
 
1893
  public static function XingVBRidOffset($version, $channelmode) {
1894
  static $XingVBRidOffsetCache = array();
1895
- if (empty($XingVBRidOffset)) {
1896
- $XingVBRidOffset = array (
1897
  '1' => array ('mono' => 0x15, // 4 + 17 = 21
1898
  'stereo' => 0x24, // 4 + 32 = 36
1899
  'joint stereo' => 0x24,
@@ -1913,9 +2016,14 @@ class getid3_mp3 extends getid3_handler
1913
  )
1914
  );
1915
  }
1916
- return $XingVBRidOffset[$version][$channelmode];
1917
  }
1918
 
 
 
 
 
 
1919
  public static function LAMEvbrMethodLookup($VBRmethodID) {
1920
  static $LAMEvbrMethodLookup = array(
1921
  0x00 => 'unknown',
@@ -1932,6 +2040,11 @@ class getid3_mp3 extends getid3_handler
1932
  return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
1933
  }
1934
 
 
 
 
 
 
1935
  public static function LAMEmiscStereoModeLookup($StereoModeID) {
1936
  static $LAMEmiscStereoModeLookup = array(
1937
  0 => 'mono',
@@ -1946,6 +2059,11 @@ class getid3_mp3 extends getid3_handler
1946
  return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
1947
  }
1948
 
 
 
 
 
 
1949
  public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) {
1950
  static $LAMEmiscSourceSampleFrequencyLookup = array(
1951
  0 => '<= 32 kHz',
@@ -1956,6 +2074,11 @@ class getid3_mp3 extends getid3_handler
1956
  return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
1957
  }
1958
 
 
 
 
 
 
1959
  public static function LAMEsurroundInfoLookup($SurroundInfoID) {
1960
  static $LAMEsurroundInfoLookup = array(
1961
  0 => 'no surround info',
@@ -1966,6 +2089,11 @@ class getid3_mp3 extends getid3_handler
1966
  return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
1967
  }
1968
 
 
 
 
 
 
1969
  public static function LAMEpresetUsedLookup($LAMEtag) {
1970
 
1971
  if ($LAMEtag['preset_used_id'] == 0) {
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.mp3.php //
24
 
25
  class getid3_mp3 extends getid3_handler
26
  {
27
+ /**
28
+ * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow,
29
+ * unrecommended, but may provide data from otherwise-unusable files.
30
+ *
31
+ * @var bool
32
+ */
33
+ public $allow_bruteforce = false;
34
+
35
+ /**
36
+ * @return bool
37
+ */
38
  public function Analyze() {
39
  $info = &$this->getid3->info;
40
 
42
 
43
  if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
44
  if ($this->allow_bruteforce) {
45
+ $this->error('Rescanning file in BruteForce mode');
46
+ $this->getOnlyMPEGaudioInfoBruteForce();
47
  }
48
  }
49
 
80
  }
81
 
82
  }
83
+ $this->warning($synchoffsetwarning);
84
 
85
  }
86
 
142
  break;
143
 
144
  default:
145
+ $this->warning('Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"');
146
  break;
147
  }
148
  }
160
 
161
  // Calculate playtime
162
  if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
163
+ // https://github.com/JamesHeinrich/getID3/issues/161
164
+ // VBR header frame contains ~0.026s of silent audio data, but is not actually part of the original encoding and should be ignored
165
+ $xingVBRheaderFrameLength = ((isset($info['mpeg']['audio']['VBR_frames']) && isset($info['mpeg']['audio']['framelength'])) ? $info['mpeg']['audio']['framelength'] : 0);
166
+
167
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset'] - $xingVBRheaderFrameLength) * 8 / $info['audio']['bitrate'];
168
  }
169
 
170
  $info['audio']['encoder_options'] = $this->GuessEncoderOptions();
172
  return true;
173
  }
174
 
175
+ /**
176
+ * @return string
177
+ */
178
  public function GuessEncoderOptions() {
179
  // shortcuts
180
  $info = &$this->getid3->info;
181
+ $thisfile_mpeg_audio = array();
182
+ $thisfile_mpeg_audio_lame = array();
183
  if (!empty($info['mpeg']['audio'])) {
184
  $thisfile_mpeg_audio = &$info['mpeg']['audio'];
185
  if (!empty($thisfile_mpeg_audio['LAME'])) {
194
 
195
  $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
196
 
197
+ } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && isset($thisfile_mpeg_audio_lame['preset_used_id']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
198
 
199
  $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
200
 
420
  return $encoder_options;
421
  }
422
 
423
+ /**
424
+ * @param int $offset
425
+ * @param array $info
426
+ * @param bool $recursivesearch
427
+ * @param bool $ScanAsCBR
428
+ * @param bool $FastMPEGheaderScan
429
+ *
430
+ * @return bool
431
+ */
432
  public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
433
  static $MPEGaudioVersionLookup;
434
  static $MPEGaudioLayerLookup;
448
  }
449
 
450
  if ($this->fseek($offset) != 0) {
451
+ $this->error('decodeMPEGaudioHeader() failed to seek to next offset at '.$offset);
452
  return false;
453
  }
454
  //$headerstring = $this->fread(1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
461
  // and $cc... is the audio data
462
 
463
  $head4 = substr($headerstring, 0, 4);
464
+ $head4_key = getid3_lib::PrintHexBytes($head4, true, false, false);
465
  static $MPEGaudioHeaderDecodeCache = array();
466
+ if (isset($MPEGaudioHeaderDecodeCache[$head4_key])) {
467
+ $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4_key];
468
  } else {
469
  $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4);
470
+ $MPEGaudioHeaderDecodeCache[$head4_key] = $MPEGheaderRawArray;
471
  }
472
 
473
  static $MPEGaudioHeaderValidCache = array();
474
+ if (!isset($MPEGaudioHeaderValidCache[$head4_key])) { // Not in cache
475
+ //$MPEGaudioHeaderValidCache[$head4_key] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)
476
+ $MPEGaudioHeaderValidCache[$head4_key] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);
477
  }
478
 
479
  // shortcut
482
  }
483
  $thisfile_mpeg_audio = &$info['mpeg']['audio'];
484
 
485
+ if ($MPEGaudioHeaderValidCache[$head4_key]) {
 
486
  $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
487
  } else {
488
+ $this->error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
489
  return false;
490
  }
491
 
513
 
514
  if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
515
  // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
516
+ $this->warning('Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1');
517
  $thisfile_mpeg_audio['raw']['bitrate'] = 0;
518
  }
519
  $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
535
  if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
536
  // these are ok
537
  } else {
538
+ $this->error($thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.');
539
  return false;
540
  }
541
  break;
546
  if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
547
  // these are ok
548
  } else {
549
+ $this->error(intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.');
550
  return false;
551
  }
552
  break;
568
  if (isset($thisfile_mpeg_audio['framelength'])) {
569
  $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength'];
570
  } else {
571
+ $this->error('Frame at offset('.$offset.') is has an invalid frame length.');
572
  return false;
573
  }
574
 
585
 
586
  $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
587
  $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer';
588
+ $info['audio']['codec'] = 'Fraunhofer';
589
 
590
  $SideInfoData = substr($headerstring, 4 + 2, 32);
591
 
678
  $used_filesize = $thisfile_mpeg_audio['VBR_bytes'];
679
  } elseif (!empty($info['filesize'])) {
680
  $used_filesize = $info['filesize'];
681
+ $used_filesize -= (isset($info['id3v2']['headerlength']) ? intval($info['id3v2']['headerlength']) : 0);
682
  $used_filesize -= (isset($info['id3v1']) ? 128 : 0);
683
  $used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0);
684
+ $this->warning('MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes');
685
  }
686
 
687
  $framelengthfloat = $used_filesize / $thisfile_mpeg_audio['VBR_frames'];
871
  $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
872
  $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
873
  if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
874
+ $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
875
  }
876
  if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
877
  // this may change if 3.90.4 ever comes out
915
  $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
916
  }
917
  if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
918
+ $this->warning('VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.');
919
  }
920
  }
921
 
942
  // $this->fseek($prenullbytefileoffset);
943
  // if ($PossibleNullByte === "\x00") {
944
  $info['avdataend']--;
945
+ // $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
946
  // } else {
947
+ // $this->warning('Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)');
948
  // }
949
  } else {
950
+ $this->warning('Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)');
951
  }
952
  }
953
  }
965
  $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
966
  }
967
  } else {
968
+ $this->error('Error calculating frame length of free-format MP3 without Xing/LAME header');
969
  }
970
  }
971
  }
1106
  return true;
1107
  }
1108
 
1109
+ /**
1110
+ * @param int $offset
1111
+ * @param int $nextframetestoffset
1112
+ * @param bool $ScanAsCBR
1113
+ *
1114
+ * @return bool
1115
+ */
1116
  public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
1117
  $info = &$this->getid3->info;
1118
+ $firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
1119
  $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
1120
 
1121
  for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
1125
  return true;
1126
  }
1127
 
1128
+ $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1129
  if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
1130
  if ($ScanAsCBR) {
1131
  // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
1139
  if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) {
1140
  $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
1141
  } else {
1142
+ $this->error('Frame at offset ('.$offset.') is has an invalid frame length.');
1143
  return false;
1144
  }
1145
 
1151
  } else {
1152
 
1153
  // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
1154
+ $this->warning('Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.');
1155
 
1156
  return false;
1157
  }
1159
  return true;
1160
  }
1161
 
1162
+ /**
1163
+ * @param int $offset
1164
+ * @param bool $deepscan
1165
+ *
1166
+ * @return int|false
1167
+ */
1168
  public function FreeFormatFrameLength($offset, $deepscan=false) {
1169
  $info = &$this->getid3->info;
1170
 
1200
  $framelength = $framelength2;
1201
  }
1202
  if (!$framelength) {
1203
+ $this->error('Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset);
1204
  return false;
1205
  } else {
1206
+ $this->warning('ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)');
1207
  $info['audio']['codec'] = 'LAME';
1208
  $info['audio']['encoder'] = 'LAME3.88';
1209
  $SyncPattern1 = substr($SyncPattern1, 0, 3);
1230
  $ActualFrameLengthValues[] = ($framelength + 1);
1231
  $nextoffset++;
1232
  } else {
1233
+ $this->error('Did not find expected free-format sync pattern at offset '.$nextoffset);
1234
  return false;
1235
  }
1236
  $nextoffset += $framelength;
1242
  return $framelength;
1243
  }
1244
 
1245
+ /**
1246
+ * @return bool
1247
+ */
1248
  public function getOnlyMPEGaudioInfoBruteForce() {
1249
  $MPEGaudioHeaderDecodeCache = array();
1250
  $MPEGaudioHeaderValidCache = array();
1331
  getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
1332
  if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
1333
  $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
1334
+ $this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.');
1335
  foreach ($Distribution as $key1 => $value1) {
1336
  foreach ($value1 as $key2 => $value2) {
1337
  $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
1358
  $info['mpeg']['audio']['version_distribution'] = $Distribution['version'];
1359
  $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding'];
1360
  if (count($Distribution['version']) > 1) {
1361
+ $this->error('Corrupt file - more than one MPEG version detected');
1362
  }
1363
  if (count($Distribution['layer']) > 1) {
1364
+ $this->error('Corrupt file - more than one MPEG layer detected');
1365
  }
1366
  if (count($Distribution['frequency']) > 1) {
1367
+ $this->error('Corrupt file - more than one MPEG sample rate detected');
1368
  }
1369
 
1370
 
1376
  }
1377
  $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']);
1378
  if ($info['mpeg']['audio']['frame_count'] == 0) {
1379
+ $this->error('no MPEG audio frames found');
1380
  return false;
1381
  }
1382
  $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']);
1392
  return true;
1393
  }
1394
 
1395
+ /**
1396
+ * @param int $avdataoffset
1397
+ * @param bool $BitrateHistogram
1398
+ *
1399
+ * @return bool
1400
+ */
1401
  public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) {
1402
  // looks for synch, decodes MPEG audio header
1403
 
1407
  static $MPEGaudioLayerLookup;
1408
  static $MPEGaudioBitrateLookup;
1409
  if (empty($MPEGaudioVersionLookup)) {
1410
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
1411
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
1412
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
 
1413
  }
1414
 
1415
  $this->fseek($avdataoffset);
1416
  $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
1417
  if ($sync_seek_buffer_size <= 0) {
1418
+ $this->error('Invalid $sync_seek_buffer_size at offset '.$avdataoffset);
1419
  return false;
1420
  }
1421
  $header = $this->fread($sync_seek_buffer_size);
1426
 
1427
  if ($SynchSeekOffset > $sync_seek_buffer_size) {
1428
  // if a synch's not found within the first 128k bytes, then give up
1429
+ $this->error('Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB');
1430
  if (isset($info['audio']['bitrate'])) {
1431
  unset($info['audio']['bitrate']);
1432
  }
1440
 
1441
  } elseif (feof($this->getid3->fp)) {
1442
 
1443
+ $this->error('Could not find valid MPEG audio synch before end of file');
1444
  if (isset($info['audio']['bitrate'])) {
1445
  unset($info['audio']['bitrate']);
1446
  }
1455
  }
1456
 
1457
  if (($SynchSeekOffset + 1) >= strlen($header)) {
1458
+ $this->error('Could not find valid MPEG synch before end of file');
1459
  return false;
1460
  }
1461
 
1462
  if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
1463
+ $FirstFrameAVDataOffset = null;
1464
  if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
1465
  $FirstFrameThisfileInfo = $info;
1466
  $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
1484
  $info['audio']['dataformat'] = 'mp3';
1485
  break;
1486
  }
1487
+ if (isset($FirstFrameThisfileInfo) && isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
1488
  if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
1489
  // If there is garbage data between a valid VBR header frame and a sequence
1490
  // of valid MPEG-audio frames the VBR data is no longer discarded.
1499
  if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
1500
  $info = $dummy;
1501
  $info['avdataoffset'] = $GarbageOffsetEnd;
1502
+ $this->warning('apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
1503
  } else {
1504
+ $this->warning('using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
1505
  }
1506
  }
1507
  }
1566
  }
1567
  }
1568
  $synchstartoffset = $scan_start_offset[$current_segment];
1569
+ while (($synchstartoffset < $info['avdataend']) && $this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
1570
  $FastMode = true;
1571
  $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
1572
 
1594
  }
1595
  }
1596
  if ($pct_data_scanned > 0) {
1597
+ $this->warning('too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.');
1598
  foreach ($info['mpeg']['audio'] as $key1 => $value1) {
1599
  if (!preg_match('#_distribution$#i', $key1)) {
1600
  continue;
1606
  }
1607
 
1608
  if ($SynchErrorsFound > 0) {
1609
+ $this->warning('Found '.$SynchErrorsFound.' synch errors in histogram analysis');
1610
  //return false;
1611
  }
1612
 
1619
  }
1620
  }
1621
  if ($framecounter == 0) {
1622
+ $this->error('Corrupt MP3 file: framecounter == zero');
1623
  return false;
1624
  }
1625
  $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter);
1654
 
1655
  if (empty($info['mpeg']['audio'])) {
1656
 
1657
+ $this->error('could not find valid MPEG synch before end of file');
1658
  if (isset($info['audio']['bitrate'])) {
1659
  unset($info['audio']['bitrate']);
1660
  }
1677
  return true;
1678
  }
1679
 
1680
+ /**
1681
+ * @return array
1682
+ */
1683
  public static function MPEGaudioVersionArray() {
1684
  static $MPEGaudioVersion = array('2.5', false, '2', '1');
1685
  return $MPEGaudioVersion;
1686
  }
1687
 
1688
+ /**
1689
+ * @return array
1690
+ */
1691
  public static function MPEGaudioLayerArray() {
1692
  static $MPEGaudioLayer = array(false, 3, 2, 1);
1693
  return $MPEGaudioLayer;
1694
  }
1695
 
1696
+ /**
1697
+ * @return array
1698
+ */
1699
  public static function MPEGaudioBitrateArray() {
1700
  static $MPEGaudioBitrate;
1701
  if (empty($MPEGaudioBitrate)) {
1715
  return $MPEGaudioBitrate;
1716
  }
1717
 
1718
+ /**
1719
+ * @return array
1720
+ */
1721
  public static function MPEGaudioFrequencyArray() {
1722
  static $MPEGaudioFrequency;
1723
  if (empty($MPEGaudioFrequency)) {
1730
  return $MPEGaudioFrequency;
1731
  }
1732
 
1733
+ /**
1734
+ * @return array
1735
+ */
1736
  public static function MPEGaudioChannelModeArray() {
1737
  static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
1738
  return $MPEGaudioChannelMode;
1739
  }
1740
 
1741
+ /**
1742
+ * @return array
1743
+ */
1744
  public static function MPEGaudioModeExtensionArray() {
1745
  static $MPEGaudioModeExtension;
1746
  if (empty($MPEGaudioModeExtension)) {
1753
  return $MPEGaudioModeExtension;
1754
  }
1755
 
1756
+ /**
1757
+ * @return array
1758
+ */
1759
  public static function MPEGaudioEmphasisArray() {
1760
  static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
1761
  return $MPEGaudioEmphasis;
1762
  }
1763
 
1764
+ /**
1765
+ * @param string $head4
1766
+ * @param bool $allowBitrate15
1767
+ *
1768
+ * @return bool
1769
+ */
1770
  public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) {
1771
  return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
1772
  }
1773
 
1774
+ /**
1775
+ * @param array $rawarray
1776
+ * @param bool $echoerrors
1777
+ * @param bool $allowBitrate15
1778
+ *
1779
+ * @return bool
1780
+ */
1781
  public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
1782
  if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
1783
  return false;
1850
  return true;
1851
  }
1852
 
1853
+ /**
1854
+ * @param string $Header4Bytes
1855
+ *
1856
+ * @return array|false
1857
+ */
1858
  public static function MPEGaudioHeaderDecode($Header4Bytes) {
1859
  // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
1860
  // A - Frame sync (all bits set)
1892
  return $MPEGrawHeader;
1893
  }
1894
 
1895
+ /**
1896
+ * @param int|string $bitrate
1897
+ * @param string $version
1898
+ * @param string $layer
1899
+ * @param bool $padding
1900
+ * @param int $samplerate
1901
+ *
1902
+ * @return int|false
1903
+ */
1904
  public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) {
1905
  static $AudioFrameLengthCache = array();
1906
 
1962
  return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
1963
  }
1964
 
1965
+ /**
1966
+ * @param float|int $bit_rate
1967
+ *
1968
+ * @return int|float|string
1969
+ */
1970
  public static function ClosestStandardMP3Bitrate($bit_rate) {
1971
  static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
1972
  static $bit_rate_table = array (0=>'-');
1987
  return $bit_rate_table[$round_bit_rate];
1988
  }
1989
 
1990
+ /**
1991
+ * @param string $version
1992
+ * @param string $channelmode
1993
+ *
1994
+ * @return int
1995
+ */
1996
  public static function XingVBRidOffset($version, $channelmode) {
1997
  static $XingVBRidOffsetCache = array();
1998
+ if (empty($XingVBRidOffsetCache)) {
1999
+ $XingVBRidOffsetCache = array (
2000
  '1' => array ('mono' => 0x15, // 4 + 17 = 21
2001
  'stereo' => 0x24, // 4 + 32 = 36
2002
  'joint stereo' => 0x24,
2016
  )
2017
  );
2018
  }
2019
+ return $XingVBRidOffsetCache[$version][$channelmode];
2020
  }
2021
 
2022
+ /**
2023
+ * @param int $VBRmethodID
2024
+ *
2025
+ * @return string
2026
+ */
2027
  public static function LAMEvbrMethodLookup($VBRmethodID) {
2028
  static $LAMEvbrMethodLookup = array(
2029
  0x00 => 'unknown',
2040
  return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
2041
  }
2042
 
2043
+ /**
2044
+ * @param int $StereoModeID
2045
+ *
2046
+ * @return string
2047
+ */
2048
  public static function LAMEmiscStereoModeLookup($StereoModeID) {
2049
  static $LAMEmiscStereoModeLookup = array(
2050
  0 => 'mono',
2059
  return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
2060
  }
2061
 
2062
+ /**
2063
+ * @param int $SourceSampleFrequencyID
2064
+ *
2065
+ * @return string
2066
+ */
2067
  public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) {
2068
  static $LAMEmiscSourceSampleFrequencyLookup = array(
2069
  0 => '<= 32 kHz',
2074
  return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
2075
  }
2076
 
2077
+ /**
2078
+ * @param int $SurroundInfoID
2079
+ *
2080
+ * @return string
2081
+ */
2082
  public static function LAMEsurroundInfoLookup($SurroundInfoID) {
2083
  static $LAMEsurroundInfoLookup = array(
2084
  0 => 'no surround info',
2089
  return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
2090
  }
2091
 
2092
+ /**
2093
+ * @param array $LAMEtag
2094
+ *
2095
+ * @return string
2096
+ */
2097
  public static function LAMEpresetUsedLookup($LAMEtag) {
2098
 
2099
  if ($LAMEtag['preset_used_id'] == 0) {
lib/getid3/module.audio.mpc.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.mpc.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_mpc extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -50,16 +52,17 @@ class getid3_mpc extends getid3_handler
50
 
51
  } else {
52
 
53
- $info['error'][] = 'Expecting "MP+" or "MPCK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($MPCheaderData, 0, 4)).'"';
54
  unset($info['fileformat']);
55
  unset($info['mpc']);
56
  return false;
57
 
58
  }
59
- return false;
60
  }
61
 
62
-
 
 
63
  public function ParseMPCsv8() {
64
  // this is SV8
65
  // http://trac.musepack.net/trac/wiki/SV8Specification
@@ -83,13 +86,13 @@ class getid3_mpc extends getid3_handler
83
  $thisPacket['key'] = substr($MPCheaderData, 0, $keyNameSize);
84
  $thisPacket['key_name'] = $this->MPCsv8PacketName($thisPacket['key']);
85
  if ($thisPacket['key'] == $thisPacket['key_name']) {
86
- $info['error'][] = 'Found unexpected key value "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
87
  return false;
88
  }
89
  $packetLength = 0;
90
  $thisPacket['packet_size'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $keyNameSize), $packetLength); // includes keyname and packet_size field
91
  if ($thisPacket['packet_size'] === false) {
92
- $info['error'][] = 'Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize);
93
  return false;
94
  }
95
  $packet_offset += $packetLength;
@@ -195,7 +198,7 @@ class getid3_mpc extends getid3_handler
195
  break;
196
 
197
  default:
198
- $info['error'][] = 'Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
199
  return false;
200
  break;
201
  }
@@ -208,6 +211,9 @@ class getid3_mpc extends getid3_handler
208
  return true;
209
  }
210
 
 
 
 
211
  public function ParseMPCsv7() {
212
  // this is SV7
213
  // http://www.uni-jena.de/~pfk/mpp/sv8/header.html
@@ -229,7 +235,7 @@ class getid3_mpc extends getid3_handler
229
  $offset += 4;
230
 
231
  if ($thisfile_mpc_header['stream_version_major'] != 7) {
232
- $info['error'][] = 'Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')';
233
  return false;
234
  }
235
 
@@ -268,7 +274,7 @@ class getid3_mpc extends getid3_handler
268
  $thisfile_mpc_header['profile'] = $this->MPCprofileNameLookup($thisfile_mpc_header['raw']['profile']);
269
  $thisfile_mpc_header['sample_rate'] = $this->MPCfrequencyLookup($thisfile_mpc_header['raw']['sample_rate']);
270
  if ($thisfile_mpc_header['sample_rate'] == 0) {
271
- $info['error'][] = 'Corrupt MPC file: frequency == zero';
272
  return false;
273
  }
274
  $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
@@ -276,7 +282,7 @@ class getid3_mpc extends getid3_handler
276
 
277
  $info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate'];
278
  if ($info['playtime_seconds'] == 0) {
279
- $info['error'][] = 'Corrupt MPC file: playtime_seconds == zero';
280
  return false;
281
  }
282
 
@@ -322,6 +328,9 @@ class getid3_mpc extends getid3_handler
322
  return true;
323
  }
324
 
 
 
 
325
  public function ParseMPCsv6() {
326
  // this is SV4 - SV6
327
 
@@ -377,7 +386,7 @@ class getid3_mpc extends getid3_handler
377
  }
378
 
379
  if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) {
380
- $info['warning'][] = 'Block size expected to be 1, actual value found: '.$thisfile_mpc_header['block_size'];
381
  }
382
 
383
  $thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7
@@ -397,7 +406,11 @@ class getid3_mpc extends getid3_handler
397
  return true;
398
  }
399
 
400
-
 
 
 
 
401
  public function MPCprofileNameLookup($profileid) {
402
  static $MPCprofileNameLookup = array(
403
  0 => 'no profile',
@@ -420,6 +433,11 @@ class getid3_mpc extends getid3_handler
420
  return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid');
421
  }
422
 
 
 
 
 
 
423
  public function MPCfrequencyLookup($frequencyid) {
424
  static $MPCfrequencyLookup = array(
425
  0 => 44100,
@@ -430,6 +448,11 @@ class getid3_mpc extends getid3_handler
430
  return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid');
431
  }
432
 
 
 
 
 
 
433
  public function MPCpeakDBLookup($intvalue) {
434
  if ($intvalue > 0) {
435
  return ((log10($intvalue) / log10(2)) - 15) * 6;
@@ -437,6 +460,11 @@ class getid3_mpc extends getid3_handler
437
  return false;
438
  }
439
 
 
 
 
 
 
440
  public function MPCencoderVersionLookup($encoderversion) {
441
  //Encoder version * 100 (106 = 1.06)
442
  //EncoderVersion % 10 == 0 Release (1.0)
@@ -464,6 +492,13 @@ class getid3_mpc extends getid3_handler
464
  return number_format($encoderversion / 100, 2).' alpha';
465
  }
466
 
 
 
 
 
 
 
 
467
  public function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) {
468
  $packet_size = 0;
469
  for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) {
@@ -488,6 +523,11 @@ class getid3_mpc extends getid3_handler
488
  return $packet_size;
489
  }
490
 
 
 
 
 
 
491
  public function MPCsv8PacketName($packetKey) {
492
  static $MPCsv8PacketName = array();
493
  if (empty($MPCsv8PacketName)) {
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.mpc.php //
17
 
18
  class getid3_mpc extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
52
 
53
  } else {
54
 
55
+ $this->error('Expecting "MP+" or "MPCK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($MPCheaderData, 0, 4)).'"');
56
  unset($info['fileformat']);
57
  unset($info['mpc']);
58
  return false;
59
 
60
  }
 
61
  }
62
 
63
+ /**
64
+ * @return bool
65
+ */
66
  public function ParseMPCsv8() {
67
  // this is SV8
68
  // http://trac.musepack.net/trac/wiki/SV8Specification
86
  $thisPacket['key'] = substr($MPCheaderData, 0, $keyNameSize);
87
  $thisPacket['key_name'] = $this->MPCsv8PacketName($thisPacket['key']);
88
  if ($thisPacket['key'] == $thisPacket['key_name']) {
89
+ $this->error('Found unexpected key value "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']);
90
  return false;
91
  }
92
  $packetLength = 0;
93
  $thisPacket['packet_size'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $keyNameSize), $packetLength); // includes keyname and packet_size field
94
  if ($thisPacket['packet_size'] === false) {
95
+ $this->error('Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize));
96
  return false;
97
  }
98
  $packet_offset += $packetLength;
198
  break;
199
 
200
  default:
201
+ $this->error('Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']);
202
  return false;
203
  break;
204
  }
211
  return true;
212
  }
213
 
214
+ /**
215
+ * @return bool
216
+ */
217
  public function ParseMPCsv7() {
218
  // this is SV7
219
  // http://www.uni-jena.de/~pfk/mpp/sv8/header.html
235
  $offset += 4;
236
 
237
  if ($thisfile_mpc_header['stream_version_major'] != 7) {
238
+ $this->error('Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')');
239
  return false;
240
  }
241
 
274
  $thisfile_mpc_header['profile'] = $this->MPCprofileNameLookup($thisfile_mpc_header['raw']['profile']);
275
  $thisfile_mpc_header['sample_rate'] = $this->MPCfrequencyLookup($thisfile_mpc_header['raw']['sample_rate']);
276
  if ($thisfile_mpc_header['sample_rate'] == 0) {
277
+ $this->error('Corrupt MPC file: frequency == zero');
278
  return false;
279
  }
280
  $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
282
 
283
  $info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate'];
284
  if ($info['playtime_seconds'] == 0) {
285
+ $this->error('Corrupt MPC file: playtime_seconds == zero');
286
  return false;
287
  }
288
 
328
  return true;
329
  }
330
 
331
+ /**
332
+ * @return bool
333
+ */
334
  public function ParseMPCsv6() {
335
  // this is SV4 - SV6
336
 
386
  }
387
 
388
  if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) {
389
+ $this->warning('Block size expected to be 1, actual value found: '.$thisfile_mpc_header['block_size']);
390
  }
391
 
392
  $thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7
406
  return true;
407
  }
408
 
409
+ /**
410
+ * @param int $profileid
411
+ *
412
+ * @return string
413
+ */
414
  public function MPCprofileNameLookup($profileid) {
415
  static $MPCprofileNameLookup = array(
416
  0 => 'no profile',
433
  return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid');
434
  }
435
 
436
+ /**
437
+ * @param int $frequencyid
438
+ *
439
+ * @return int|string
440
+ */
441
  public function MPCfrequencyLookup($frequencyid) {
442
  static $MPCfrequencyLookup = array(
443
  0 => 44100,
448
  return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid');
449
  }
450
 
451
+ /**
452
+ * @param int $intvalue
453
+ *
454
+ * @return float|false
455
+ */
456
  public function MPCpeakDBLookup($intvalue) {
457
  if ($intvalue > 0) {
458
  return ((log10($intvalue) / log10(2)) - 15) * 6;
460
  return false;
461
  }
462
 
463
+ /**
464
+ * @param int $encoderversion
465
+ *
466
+ * @return string
467
+ */
468
  public function MPCencoderVersionLookup($encoderversion) {
469
  //Encoder version * 100 (106 = 1.06)
470
  //EncoderVersion % 10 == 0 Release (1.0)
492
  return number_format($encoderversion / 100, 2).' alpha';
493
  }
494
 
495
+ /**
496
+ * @param string $data
497
+ * @param int $packetLength
498
+ * @param int $maxHandledPacketLength
499
+ *
500
+ * @return int|false
501
+ */
502
  public function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) {
503
  $packet_size = 0;
504
  for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) {
523
  return $packet_size;
524
  }
525
 
526
+ /**
527
+ * @param string $packetKey
528
+ *
529
+ * @return string
530
+ */
531
  public function MPCsv8PacketName($packetKey) {
532
  static $MPCsv8PacketName = array();
533
  if (empty($MPCsv8PacketName)) {
lib/getid3/module.audio.ogg.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.ogg.php //
@@ -18,7 +18,11 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE
18
 
19
  class getid3_ogg extends getid3_handler
20
  {
21
- // http://xiph.org/vorbis/doc/Vorbis_I_spec.html
 
 
 
 
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
@@ -26,13 +30,13 @@ class getid3_ogg extends getid3_handler
26
 
27
  // Warn about illegal tags - only vorbiscomments are allowed
28
  if (isset($info['id3v2'])) {
29
- $info['warning'][] = 'Illegal ID3v2 tag present.';
30
  }
31
  if (isset($info['id3v1'])) {
32
- $info['warning'][] = 'Illegal ID3v1 tag present.';
33
  }
34
  if (isset($info['ape'])) {
35
- $info['warning'][] = 'Illegal APE tag present.';
36
  }
37
 
38
 
@@ -44,7 +48,7 @@ class getid3_ogg extends getid3_handler
44
  $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
45
 
46
  if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
47
- $info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';
48
  unset($info['fileformat']);
49
  unset($info['ogg']);
50
  return false;
@@ -65,7 +69,7 @@ class getid3_ogg extends getid3_handler
65
 
66
  } elseif (substr($filedata, 0, 8) == 'OpusHead') {
67
 
68
- if( $this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) == false ) {
69
  return false;
70
  }
71
 
@@ -179,7 +183,7 @@ class getid3_ogg extends getid3_handler
179
  if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
180
  $info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
181
  }
182
- $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable';
183
 
184
 
185
  } elseif (substr($filedata, 0, 8) == "fishead\x00") {
@@ -240,7 +244,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
240
  } elseif (substr($filedata, 1, 6) == 'theora') {
241
 
242
  $info['video']['dataformat'] = 'theora1';
243
- $info['error'][] = 'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']';
244
  //break;
245
 
246
  } elseif (substr($filedata, 1, 6) == 'vorbis') {
@@ -248,7 +252,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
248
  $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
249
 
250
  } else {
251
- $info['error'][] = 'unexpected';
252
  //break;
253
  }
254
  //} while ($oggpageinfo['page_seqno'] == 0);
@@ -256,12 +260,37 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
256
 
257
  $this->fseek($oggpageinfo['page_start_offset']);
258
 
259
- $info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
260
  //return false;
261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  } else {
263
 
264
- $info['error'][] = 'Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
265
  unset($info['ogg']);
266
  unset($info['mime_type']);
267
  return false;
@@ -284,7 +313,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
284
  case 'flac':
285
  $flac = new getid3_flac($this->getid3);
286
  if (!$flac->parseMETAdata()) {
287
- $info['error'][] = 'Failed to parse FLAC headers';
288
  return false;
289
  }
290
  unset($flac);
@@ -299,7 +328,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
299
  $filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
300
  $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 0, 8); // hard-coded to 'OpusTags'
301
  if(substr($filedata, 0, 8) != 'OpusTags') {
302
- $info['error'][] = 'Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"';
303
  return false;
304
  }
305
 
@@ -311,7 +340,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
311
  // Last Page - Number of Samples
312
  if (!getid3_lib::intValueSupported($info['avdataend'])) {
313
 
314
- $info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
315
 
316
  } else {
317
 
@@ -323,7 +352,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
323
  $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
324
  $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
325
  if ($info['ogg']['samples'] == 0) {
326
- $info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
327
  return false;
328
  }
329
  if (!empty($info['audio']['sample_rate'])) {
@@ -342,7 +371,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
342
  }
343
  if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
344
  if ($info['audio']['bitrate'] == 0) {
345
- $info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
346
  return false;
347
  }
348
  $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
@@ -378,6 +407,13 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
378
  return true;
379
  }
380
 
 
 
 
 
 
 
 
381
  public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
382
  $info = &$this->getid3->info;
383
  $info['audio']['dataformat'] = 'vorbis';
@@ -395,7 +431,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
395
  $info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
396
  $filedataoffset += 4;
397
  if ($info['ogg']['samplerate'] == 0) {
398
- $info['error'][] = 'Corrupt Ogg file: sample rate == zero';
399
  return false;
400
  }
401
  $info['audio']['sample_rate'] = $info['ogg']['samplerate'];
@@ -426,7 +462,15 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
426
  return true;
427
  }
428
 
429
- // http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
 
 
 
 
 
 
 
 
430
  public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
431
  $info = &$this->getid3->info;
432
  $info['audio']['dataformat'] = 'opus';
@@ -443,7 +487,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
443
  $filedataoffset += 1;
444
 
445
  if ($info['ogg']['pageheader']['opus']['version'] < 1 || $info['ogg']['pageheader']['opus']['version'] > 15) {
446
- $info['error'][] = 'Unknown opus version number (only accepting 1-15)';
447
  return false;
448
  }
449
 
@@ -451,14 +495,14 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
451
  $filedataoffset += 1;
452
 
453
  if ($info['ogg']['pageheader']['opus']['out_channel_count'] == 0) {
454
- $info['error'][] = 'Invalid channel count in opus header (must not be zero)';
455
  return false;
456
  }
457
 
458
  $info['ogg']['pageheader']['opus']['pre_skip'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
459
  $filedataoffset += 2;
460
 
461
- $info['ogg']['pageheader']['opus']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
462
  $filedataoffset += 4;
463
 
464
  //$info['ogg']['pageheader']['opus']['output_gain'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
@@ -467,16 +511,19 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
467
  //$info['ogg']['pageheader']['opus']['channel_mapping_family'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
468
  //$filedataoffset += 1;
469
 
470
- $info['opus']['opus_version'] = $info['ogg']['pageheader']['opus']['version'];
471
- $info['opus']['sample_rate'] = $info['ogg']['pageheader']['opus']['sample_rate'];
472
- $info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count'];
473
 
474
- $info['audio']['channels'] = $info['opus']['out_channel_count'];
475
- $info['audio']['sample_rate'] = $info['opus']['sample_rate'];
 
476
  return true;
477
  }
478
 
479
-
 
 
480
  public function ParseOggPageHeader() {
481
  // http://xiph.org/ogg/vorbis/doc/framing.html
482
  $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
@@ -489,7 +536,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
489
  return false;
490
  }
491
  if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
492
- if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) {
493
  // get some more data, unless eof, in which case fail
494
  return false;
495
  }
@@ -528,13 +575,19 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
528
  return $oggheader;
529
  }
530
 
531
- // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
 
 
 
 
532
  public function ParseVorbisComments() {
533
  $info = &$this->getid3->info;
534
 
535
  $OriginalOffset = $this->ftell();
 
536
  $commentdataoffset = 0;
537
  $VorbisCommentPage = 1;
 
538
 
539
  switch ($info['audio']['dataformat']) {
540
  case 'vorbis':
@@ -581,7 +634,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
581
 
582
  if ($i >= 10000) {
583
  // https://github.com/owncloud/music/issues/212#issuecomment-43082336
584
- $info['warning'][] = 'Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments';
585
  break;
586
  }
587
 
@@ -619,7 +672,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
619
  $commentdataoffset += 4;
620
  while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
621
  if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
622
- $info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';
623
  break 2;
624
  }
625
 
@@ -643,12 +696,12 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
643
 
644
  //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
645
  if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
646
- $info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
647
  break;
648
  }
649
  $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
650
  if ($readlength <= 0) {
651
- $info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
652
  break;
653
  }
654
  $commentdata .= $this->fread($readlength);
@@ -662,7 +715,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
662
  if (!$commentstring) {
663
 
664
  // no comment?
665
- $info['warning'][] = 'Blank Ogg comment ['.$i.']';
666
 
667
  } elseif (strstr($commentstring, '=')) {
668
 
@@ -712,7 +765,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
712
 
713
  } else {
714
 
715
- $info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
716
 
717
  }
718
  unset($ThisFileInfo_ogg_comments_raw[$i]);
@@ -765,6 +818,11 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
765
  return true;
766
  }
767
 
 
 
 
 
 
768
  public static function SpeexBandModeLookup($mode) {
769
  static $SpeexBandModeLookup = array();
770
  if (empty($SpeexBandModeLookup)) {
@@ -775,8 +833,14 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
775
  return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
776
  }
777
 
778
-
 
 
 
 
 
779
  public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
 
780
  for ($i = 0; $i < $SegmentNumber; $i++) {
781
  $segmentlength = 0;
782
  foreach ($OggInfoArray['segment_table'] as $key => $value) {
@@ -789,7 +853,11 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
789
  return $segmentlength;
790
  }
791
 
792
-
 
 
 
 
793
  public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
794
 
795
  // decrease precision
@@ -813,6 +881,11 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
813
  return round($qval, 1); // 5 or 4.9
814
  }
815
 
 
 
 
 
 
816
  public static function TheoraColorSpace($colorspace_id) {
817
  // http://www.theora.org/doc/Theora.pdf (table 6.3)
818
  static $TheoraColorSpaceLookup = array();
@@ -825,6 +898,11 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
825
  return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null);
826
  }
827
 
 
 
 
 
 
828
  public static function TheoraPixelFormat($pixelformat_id) {
829
  // http://www.theora.org/doc/Theora.pdf (table 6.4)
830
  static $TheoraPixelFormatLookup = array();
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.ogg.php //
18
 
19
  class getid3_ogg extends getid3_handler
20
  {
21
+ /**
22
+ * @link http://xiph.org/vorbis/doc/Vorbis_I_spec.html
23
+ *
24
+ * @return bool
25
+ */
26
  public function Analyze() {
27
  $info = &$this->getid3->info;
28
 
30
 
31
  // Warn about illegal tags - only vorbiscomments are allowed
32
  if (isset($info['id3v2'])) {
33
+ $this->warning('Illegal ID3v2 tag present.');
34
  }
35
  if (isset($info['id3v1'])) {
36
+ $this->warning('Illegal ID3v1 tag present.');
37
  }
38
  if (isset($info['ape'])) {
39
+ $this->warning('Illegal APE tag present.');
40
  }
41
 
42
 
48
  $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
49
 
50
  if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
51
+ $this->error('Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)');
52
  unset($info['fileformat']);
53
  unset($info['ogg']);
54
  return false;
69
 
70
  } elseif (substr($filedata, 0, 8) == 'OpusHead') {
71
 
72
+ if ($this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) === false) {
73
  return false;
74
  }
75
 
183
  if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
184
  $info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
185
  }
186
+ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable');
187
 
188
 
189
  } elseif (substr($filedata, 0, 8) == "fishead\x00") {
244
  } elseif (substr($filedata, 1, 6) == 'theora') {
245
 
246
  $info['video']['dataformat'] = 'theora1';
247
+ $this->error('Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']');
248
  //break;
249
 
250
  } elseif (substr($filedata, 1, 6) == 'vorbis') {
252
  $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
253
 
254
  } else {
255
+ $this->error('unexpected');
256
  //break;
257
  }
258
  //} while ($oggpageinfo['page_seqno'] == 0);
260
 
261
  $this->fseek($oggpageinfo['page_start_offset']);
262
 
263
+ $this->error('Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']');
264
  //return false;
265
 
266
+ } elseif (substr($filedata, 0, 5) == "\x7F".'FLAC') {
267
+ // https://xiph.org/flac/ogg_mapping.html
268
+
269
+ $info['audio']['dataformat'] = 'flac';
270
+ $info['audio']['bitrate_mode'] = 'vbr';
271
+ $info['audio']['lossless'] = true;
272
+
273
+ $info['ogg']['flac']['header']['version_major'] = ord(substr($filedata, 5, 1));
274
+ $info['ogg']['flac']['header']['version_minor'] = ord(substr($filedata, 6, 1));
275
+ $info['ogg']['flac']['header']['header_packets'] = getid3_lib::BigEndian2Int(substr($filedata, 7, 2)) + 1; // "A two-byte, big-endian binary number signifying the number of header (non-audio) packets, not including this one. This number may be zero (0x0000) to signify 'unknown' but be aware that some decoders may not be able to handle such streams."
276
+ $info['ogg']['flac']['header']['magic'] = substr($filedata, 9, 4);
277
+ if ($info['ogg']['flac']['header']['magic'] != 'fLaC') {
278
+ $this->error('Ogg-FLAC expecting "fLaC", found "'.$info['ogg']['flac']['header']['magic'].'" ('.trim(getid3_lib::PrintHexBytes($info['ogg']['flac']['header']['magic'])).')');
279
+ return false;
280
+ }
281
+ $info['ogg']['flac']['header']['STREAMINFO_bytes'] = getid3_lib::BigEndian2Int(substr($filedata, 13, 4));
282
+ $info['flac']['STREAMINFO'] = getid3_flac::parseSTREAMINFOdata(substr($filedata, 17, 34));
283
+ if (!empty($info['flac']['STREAMINFO']['sample_rate'])) {
284
+ $info['audio']['bitrate_mode'] = 'vbr';
285
+ $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate'];
286
+ $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels'];
287
+ $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
288
+ $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate'];
289
+ }
290
+
291
  } else {
292
 
293
+ $this->error('Expecting one of "vorbis", "Speex", "OpusHead", "vorbis", "fishhead", "theora", "fLaC" identifier strings, found "'.substr($filedata, 0, 8).'"');
294
  unset($info['ogg']);
295
  unset($info['mime_type']);
296
  return false;
313
  case 'flac':
314
  $flac = new getid3_flac($this->getid3);
315
  if (!$flac->parseMETAdata()) {
316
+ $this->error('Failed to parse FLAC headers');
317
  return false;
318
  }
319
  unset($flac);
328
  $filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
329
  $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 0, 8); // hard-coded to 'OpusTags'
330
  if(substr($filedata, 0, 8) != 'OpusTags') {
331
+ $this->error('Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"');
332
  return false;
333
  }
334
 
340
  // Last Page - Number of Samples
341
  if (!getid3_lib::intValueSupported($info['avdataend'])) {
342
 
343
+ $this->warning('Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
344
 
345
  } else {
346
 
352
  $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
353
  $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
354
  if ($info['ogg']['samples'] == 0) {
355
+ $this->error('Corrupt Ogg file: eos.number of samples == zero');
356
  return false;
357
  }
358
  if (!empty($info['audio']['sample_rate'])) {
371
  }
372
  if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
373
  if ($info['audio']['bitrate'] == 0) {
374
+ $this->error('Corrupt Ogg file: bitrate_audio == zero');
375
  return false;
376
  }
377
  $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
407
  return true;
408
  }
409
 
410
+ /**
411
+ * @param string $filedata
412
+ * @param int $filedataoffset
413
+ * @param array $oggpageinfo
414
+ *
415
+ * @return bool
416
+ */
417
  public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
418
  $info = &$this->getid3->info;
419
  $info['audio']['dataformat'] = 'vorbis';
431
  $info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
432
  $filedataoffset += 4;
433
  if ($info['ogg']['samplerate'] == 0) {
434
+ $this->error('Corrupt Ogg file: sample rate == zero');
435
  return false;
436
  }
437
  $info['audio']['sample_rate'] = $info['ogg']['samplerate'];
462
  return true;
463
  }
464
 
465
+ /**
466
+ * @link http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
467
+ *
468
+ * @param string $filedata
469
+ * @param int $filedataoffset
470
+ * @param array $oggpageinfo
471
+ *
472
+ * @return bool
473
+ */
474
  public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
475
  $info = &$this->getid3->info;
476
  $info['audio']['dataformat'] = 'opus';
487
  $filedataoffset += 1;
488
 
489
  if ($info['ogg']['pageheader']['opus']['version'] < 1 || $info['ogg']['pageheader']['opus']['version'] > 15) {
490
+ $this->error('Unknown opus version number (only accepting 1-15)');
491
  return false;
492
  }
493
 
495
  $filedataoffset += 1;
496
 
497
  if ($info['ogg']['pageheader']['opus']['out_channel_count'] == 0) {
498
+ $this->error('Invalid channel count in opus header (must not be zero)');
499
  return false;
500
  }
501
 
502
  $info['ogg']['pageheader']['opus']['pre_skip'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
503
  $filedataoffset += 2;
504
 
505
+ $info['ogg']['pageheader']['opus']['input_sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
506
  $filedataoffset += 4;
507
 
508
  //$info['ogg']['pageheader']['opus']['output_gain'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
511
  //$info['ogg']['pageheader']['opus']['channel_mapping_family'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
512
  //$filedataoffset += 1;
513
 
514
+ $info['opus']['opus_version'] = $info['ogg']['pageheader']['opus']['version'];
515
+ $info['opus']['sample_rate_input'] = $info['ogg']['pageheader']['opus']['input_sample_rate'];
516
+ $info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count'];
517
 
518
+ $info['audio']['channels'] = $info['opus']['out_channel_count'];
519
+ $info['audio']['sample_rate_input'] = $info['opus']['sample_rate_input'];
520
+ $info['audio']['sample_rate'] = 48000; // "All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz for playback (unless the target hardware does not support this sampling rate). However, this field may be used to resample the audio back to the original sampling rate, for example, when saving the output to a file." -- https://mf4.xiph.org/jenkins/view/opus/job/opusfile-unix/ws/doc/html/structOpusHead.html
521
  return true;
522
  }
523
 
524
+ /**
525
+ * @return array|false
526
+ */
527
  public function ParseOggPageHeader() {
528
  // http://xiph.org/ogg/vorbis/doc/framing.html
529
  $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
536
  return false;
537
  }
538
  if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
539
+ if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === '')) {
540
  // get some more data, unless eof, in which case fail
541
  return false;
542
  }
575
  return $oggheader;
576
  }
577
 
578
+ /**
579
+ * @link http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
580
+ *
581
+ * @return bool
582
+ */
583
  public function ParseVorbisComments() {
584
  $info = &$this->getid3->info;
585
 
586
  $OriginalOffset = $this->ftell();
587
+ $commentdata = null;
588
  $commentdataoffset = 0;
589
  $VorbisCommentPage = 1;
590
+ $CommentStartOffset = 0;
591
 
592
  switch ($info['audio']['dataformat']) {
593
  case 'vorbis':
634
 
635
  if ($i >= 10000) {
636
  // https://github.com/owncloud/music/issues/212#issuecomment-43082336
637
+ $this->warning('Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments');
638
  break;
639
  }
640
 
672
  $commentdataoffset += 4;
673
  while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
674
  if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
675
+ $this->warning('Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments');
676
  break 2;
677
  }
678
 
696
 
697
  //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
698
  if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
699
+ $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
700
  break;
701
  }
702
  $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
703
  if ($readlength <= 0) {
704
+ $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
705
  break;
706
  }
707
  $commentdata .= $this->fread($readlength);
715
  if (!$commentstring) {
716
 
717
  // no comment?
718
+ $this->warning('Blank Ogg comment ['.$i.']');
719
 
720
  } elseif (strstr($commentstring, '=')) {
721
 
765
 
766
  } else {
767
 
768
+ $this->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring);
769
 
770
  }
771
  unset($ThisFileInfo_ogg_comments_raw[$i]);
818
  return true;
819
  }
820
 
821
+ /**
822
+ * @param int $mode
823
+ *
824
+ * @return string|null
825
+ */
826
  public static function SpeexBandModeLookup($mode) {
827
  static $SpeexBandModeLookup = array();
828
  if (empty($SpeexBandModeLookup)) {
833
  return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
834
  }
835
 
836
+ /**
837
+ * @param array $OggInfoArray
838
+ * @param int $SegmentNumber
839
+ *
840
+ * @return int
841
+ */
842
  public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
843
+ $segmentlength = 0;
844
  for ($i = 0; $i < $SegmentNumber; $i++) {
845
  $segmentlength = 0;
846
  foreach ($OggInfoArray['segment_table'] as $key => $value) {
853
  return $segmentlength;
854
  }
855
 
856
+ /**
857
+ * @param int $nominal_bitrate
858
+ *
859
+ * @return float
860
+ */
861
  public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
862
 
863
  // decrease precision
881
  return round($qval, 1); // 5 or 4.9
882
  }
883
 
884
+ /**
885
+ * @param int $colorspace_id
886
+ *
887
+ * @return string|null
888
+ */
889
  public static function TheoraColorSpace($colorspace_id) {
890
  // http://www.theora.org/doc/Theora.pdf (table 6.3)
891
  static $TheoraColorSpaceLookup = array();
898
  return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null);
899
  }
900
 
901
+ /**
902
+ * @param int $pixelformat_id
903
+ *
904
+ * @return string|null
905
+ */
906
  public static function TheoraPixelFormat($pixelformat_id) {
907
  // http://www.theora.org/doc/Theora.pdf (table 6.4)
908
  static $TheoraPixelFormatLookup = array();
lib/getid3/module.audio.optimfrog.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.optimfrog.php //
@@ -18,7 +18,9 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
18
 
19
  class getid3_optimfrog extends getid3_handler
20
  {
21
-
 
 
22
  public function Analyze() {
23
  $info = &$this->getid3->info;
24
 
@@ -39,12 +41,14 @@ class getid3_optimfrog extends getid3_handler
39
 
40
  }
41
 
42
- $info['error'][] = 'Expecting "*RIFF" or "OFR " at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($OFRheader).'"';
43
  unset($info['fileformat']);
44
  return false;
45
  }
46
 
47
-
 
 
48
  public function ParseOptimFROGheader42() {
49
  // for fileformat of v4.21 and older
50
 
@@ -91,7 +95,9 @@ class getid3_optimfrog extends getid3_handler
91
  return true;
92
  }
93
 
94
-
 
 
95
  public function ParseOptimFROGheader45() {
96
  // for fileformat of v4.50a and higher
97
 
@@ -128,7 +134,7 @@ class getid3_optimfrog extends getid3_handler
128
  break;
129
 
130
  default:
131
- $info['warning'][] = '"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)';
132
  break;
133
  }
134
  $BlockData .= $this->fread($BlockSize);
@@ -252,7 +258,7 @@ class getid3_optimfrog extends getid3_handler
252
 
253
  $thisfile_ofr_thisblock['offset'] = $BlockOffset;
254
  $thisfile_ofr_thisblock['size'] = $BlockSize;
255
- $info['warning'][] = 'APEtag processing inside OptimFROG not supported in this version ('.$this->getid3->version().') of getID3()';
256
 
257
  $this->fseek($BlockSize, SEEK_CUR);
258
  break;
@@ -272,7 +278,7 @@ class getid3_optimfrog extends getid3_handler
272
 
273
  } else {
274
 
275
- $info['warning'][] = 'Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead';
276
  $this->fseek($BlockSize, SEEK_CUR);
277
 
278
  }
@@ -283,7 +289,7 @@ class getid3_optimfrog extends getid3_handler
283
  $thisfile_ofr_thisblock['offset'] = $BlockOffset;
284
  $thisfile_ofr_thisblock['size'] = $BlockSize;
285
 
286
- $info['warning'][] = 'Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset'];
287
  $this->fseek($BlockSize, SEEK_CUR);
288
  break;
289
  }
@@ -313,7 +319,11 @@ class getid3_optimfrog extends getid3_handler
313
  return true;
314
  }
315
 
316
-
 
 
 
 
317
  public static function OptimFROGsampleTypeLookup($SampleType) {
318
  static $OptimFROGsampleTypeLookup = array(
319
  0 => 'unsigned int (8-bit)',
@@ -331,6 +341,11 @@ class getid3_optimfrog extends getid3_handler
331
  return (isset($OptimFROGsampleTypeLookup[$SampleType]) ? $OptimFROGsampleTypeLookup[$SampleType] : false);
332
  }
333
 
 
 
 
 
 
334
  public static function OptimFROGbitsPerSampleTypeLookup($SampleType) {
335
  static $OptimFROGbitsPerSampleTypeLookup = array(
336
  0 => 8,
@@ -348,6 +363,11 @@ class getid3_optimfrog extends getid3_handler
348
  return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false);
349
  }
350
 
 
 
 
 
 
351
  public static function OptimFROGchannelConfigurationLookup($ChannelConfiguration) {
352
  static $OptimFROGchannelConfigurationLookup = array(
353
  0 => 'mono',
@@ -356,6 +376,11 @@ class getid3_optimfrog extends getid3_handler
356
  return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false);
357
  }
358
 
 
 
 
 
 
359
  public static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) {
360
  static $OptimFROGchannelConfigNumChannelsLookup = array(
361
  0 => 1,
@@ -365,13 +390,17 @@ class getid3_optimfrog extends getid3_handler
365
  }
366
 
367
 
368
-
369
  // static function OptimFROGalgorithmNameLookup($AlgorithID) {
370
  // static $OptimFROGalgorithmNameLookup = array();
371
  // return (isset($OptimFROGalgorithmNameLookup[$AlgorithID]) ? $OptimFROGalgorithmNameLookup[$AlgorithID] : false);
372
  // }
373
 
374
 
 
 
 
 
 
375
  public static function OptimFROGencoderNameLookup($EncoderID) {
376
  // version = (encoderID >> 4) + 4500
377
  // system = encoderID & 0xF
@@ -387,6 +416,11 @@ class getid3_optimfrog extends getid3_handler
387
  return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')';
388
  }
389
 
 
 
 
 
 
390
  public static function OptimFROGcompressionLookup($CompressionID) {
391
  // mode = compression >> 3
392
  // speedup = compression & 0x07
@@ -409,6 +443,11 @@ class getid3_optimfrog extends getid3_handler
409
  return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')');
410
  }
411
 
 
 
 
 
 
412
  public static function OptimFROGspeedupLookup($CompressionID) {
413
  // mode = compression >> 3
414
  // speedup = compression & 0x07
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.optimfrog.php //
18
 
19
  class getid3_optimfrog extends getid3_handler
20
  {
21
+ /**
22
+ * @return bool
23
+ */
24
  public function Analyze() {
25
  $info = &$this->getid3->info;
26
 
41
 
42
  }
43
 
44
+ $this->error('Expecting "*RIFF" or "OFR " at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($OFRheader).'"');
45
  unset($info['fileformat']);
46
  return false;
47
  }
48
 
49
+ /**
50
+ * @return bool
51
+ */
52
  public function ParseOptimFROGheader42() {
53
  // for fileformat of v4.21 and older
54
 
95
  return true;
96
  }
97
 
98
+ /**
99
+ * @return bool
100
+ */
101
  public function ParseOptimFROGheader45() {
102
  // for fileformat of v4.50a and higher
103
 
134
  break;
135
 
136
  default:
137
+ $this->warning('"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)');
138
  break;
139
  }
140
  $BlockData .= $this->fread($BlockSize);
258
 
259
  $thisfile_ofr_thisblock['offset'] = $BlockOffset;
260
  $thisfile_ofr_thisblock['size'] = $BlockSize;
261
+ $this->warning('APEtag processing inside OptimFROG not supported in this version ('.$this->getid3->version().') of getID3()');
262
 
263
  $this->fseek($BlockSize, SEEK_CUR);
264
  break;
278
 
279
  } else {
280
 
281
+ $this->warning('Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead');
282
  $this->fseek($BlockSize, SEEK_CUR);
283
 
284
  }
289
  $thisfile_ofr_thisblock['offset'] = $BlockOffset;
290
  $thisfile_ofr_thisblock['size'] = $BlockSize;
291
 
292
+ $this->warning('Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset']);
293
  $this->fseek($BlockSize, SEEK_CUR);
294
  break;
295
  }
319
  return true;
320
  }
321
 
322
+ /**
323
+ * @param int $SampleType
324
+ *
325
+ * @return string|false
326
+ */
327
  public static function OptimFROGsampleTypeLookup($SampleType) {
328
  static $OptimFROGsampleTypeLookup = array(
329
  0 => 'unsigned int (8-bit)',
341
  return (isset($OptimFROGsampleTypeLookup[$SampleType]) ? $OptimFROGsampleTypeLookup[$SampleType] : false);
342
  }
343
 
344
+ /**
345
+ * @param int $SampleType
346
+ *
347
+ * @return int|false
348
+ */
349
  public static function OptimFROGbitsPerSampleTypeLookup($SampleType) {
350
  static $OptimFROGbitsPerSampleTypeLookup = array(
351
  0 => 8,
363
  return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false);
364
  }
365
 
366
+ /**
367
+ * @param int $ChannelConfiguration
368
+ *
369
+ * @return string|false
370
+ */
371
  public static function OptimFROGchannelConfigurationLookup($ChannelConfiguration) {
372
  static $OptimFROGchannelConfigurationLookup = array(
373
  0 => 'mono',
376
  return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false);
377
  }
378
 
379
+ /**
380
+ * @param int $ChannelConfiguration
381
+ *
382
+ * @return int|false
383
+ */
384
  public static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) {
385
  static $OptimFROGchannelConfigNumChannelsLookup = array(
386
  0 => 1,
390
  }
391
 
392
 
 
393
  // static function OptimFROGalgorithmNameLookup($AlgorithID) {
394
  // static $OptimFROGalgorithmNameLookup = array();
395
  // return (isset($OptimFROGalgorithmNameLookup[$AlgorithID]) ? $OptimFROGalgorithmNameLookup[$AlgorithID] : false);
396
  // }
397
 
398
 
399
+ /**
400
+ * @param int $EncoderID
401
+ *
402
+ * @return string
403
+ */
404
  public static function OptimFROGencoderNameLookup($EncoderID) {
405
  // version = (encoderID >> 4) + 4500
406
  // system = encoderID & 0xF
416
  return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')';
417
  }
418
 
419
+ /**
420
+ * @param int $CompressionID
421
+ *
422
+ * @return string
423
+ */
424
  public static function OptimFROGcompressionLookup($CompressionID) {
425
  // mode = compression >> 3
426
  // speedup = compression & 0x07
443
  return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')');
444
  }
445
 
446
+ /**
447
+ * @param int $CompressionID
448
+ *
449
+ * @return string
450
+ */
451
  public static function OptimFROGspeedupLookup($CompressionID) {
452
  // mode = compression >> 3
453
  // speedup = compression & 0x07
lib/getid3/module.audio.rkau.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.shorten.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_rkau extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -25,7 +27,7 @@ class getid3_rkau extends getid3_handler
25
  $RKAUHeader = $this->fread(20);
26
  $magic = 'RKA';
27
  if (substr($RKAUHeader, 0, 3) != $magic) {
28
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"';
29
  return false;
30
  }
31
 
@@ -36,7 +38,7 @@ class getid3_rkau extends getid3_handler
36
  $info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1));
37
  $info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT);
38
  if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) {
39
- $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')';
40
  unset($info['rkau']);
41
  return false;
42
  }
@@ -50,7 +52,7 @@ class getid3_rkau extends getid3_handler
50
  $this->RKAUqualityLookup($info['rkau']);
51
 
52
  $info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1));
53
- $info['rkau']['flags']['joint_stereo'] = (bool) (!($info['rkau']['raw']['flags'] & 0x01));
54
  $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02);
55
  $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04);
56
 
@@ -76,7 +78,11 @@ class getid3_rkau extends getid3_handler
76
 
77
  }
78
 
79
-
 
 
 
 
80
  public function RKAUqualityLookup(&$RKAUdata) {
81
  $level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4;
82
  $quality = $RKAUdata['raw']['quality'] & 0x0F;
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.shorten.php //
17
 
18
  class getid3_rkau extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
27
  $RKAUHeader = $this->fread(20);
28
  $magic = 'RKA';
29
  if (substr($RKAUHeader, 0, 3) != $magic) {
30
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"');
31
  return false;
32
  }
33
 
38
  $info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1));
39
  $info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT);
40
  if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) {
41
+ $this->error('This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')');
42
  unset($info['rkau']);
43
  return false;
44
  }
52
  $this->RKAUqualityLookup($info['rkau']);
53
 
54
  $info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1));
55
+ $info['rkau']['flags']['joint_stereo'] = !($info['rkau']['raw']['flags'] & 0x01);
56
  $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02);
57
  $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04);
58
 
78
 
79
  }
80
 
81
+ /**
82
+ * @param array $RKAUdata
83
+ *
84
+ * @return bool
85
+ */
86
  public function RKAUqualityLookup(&$RKAUdata) {
87
  $level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4;
88
  $quality = $RKAUdata['raw']['quality'] & 0x0F;
lib/getid3/module.audio.shorten.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.shorten.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_shorten extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -26,7 +28,7 @@ class getid3_shorten extends getid3_handler
26
  $ShortenHeader = $this->fread(8);
27
  $magic = 'ajkg';
28
  if (substr($ShortenHeader, 0, 4) != $magic) {
29
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"';
30
  return false;
31
  }
32
  $info['fileformat'] = 'shn';
@@ -38,7 +40,7 @@ class getid3_shorten extends getid3_handler
38
 
39
  $this->fseek($info['avdataend'] - 12);
40
  $SeekTableSignatureTest = $this->fread(12);
41
- $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK');
42
  if ($info['shn']['seektable']['present']) {
43
  $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
44
  $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length'];
@@ -47,7 +49,7 @@ class getid3_shorten extends getid3_handler
47
  $magic = 'SEEK';
48
  if ($SeekTableMagic != $magic) {
49
 
50
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"';
51
  return false;
52
 
53
  } else {
@@ -114,7 +116,7 @@ class getid3_shorten extends getid3_handler
114
  }
115
 
116
  if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
117
- $info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files';
118
  return false;
119
  }
120
 
@@ -123,7 +125,7 @@ class getid3_shorten extends getid3_handler
123
  $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
124
  foreach ($RequiredFiles as $required_file) {
125
  if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
126
- $info['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist';
127
  return false;
128
  }
129
  }
@@ -137,7 +139,7 @@ class getid3_shorten extends getid3_handler
137
  $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
138
  }
139
  if (!$shorten_present) {
140
- $info['error'][] = 'shorten binary was not found in path or /usr/local/bin';
141
  return false;
142
  }
143
  $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64';
@@ -162,7 +164,7 @@ class getid3_shorten extends getid3_handler
162
 
163
  } else {
164
 
165
- $info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime';
166
  return false;
167
 
168
  }
@@ -171,7 +173,7 @@ class getid3_shorten extends getid3_handler
171
 
172
  } else {
173
 
174
- $info['error'][] = 'shorten failed to decode file to WAV for parsing';
175
  return false;
176
 
177
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.shorten.php //
17
 
18
  class getid3_shorten extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
28
  $ShortenHeader = $this->fread(8);
29
  $magic = 'ajkg';
30
  if (substr($ShortenHeader, 0, 4) != $magic) {
31
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"');
32
  return false;
33
  }
34
  $info['fileformat'] = 'shn';
40
 
41
  $this->fseek($info['avdataend'] - 12);
42
  $SeekTableSignatureTest = $this->fread(12);
43
+ $info['shn']['seektable']['present'] = substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK';
44
  if ($info['shn']['seektable']['present']) {
45
  $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
46
  $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length'];
49
  $magic = 'SEEK';
50
  if ($SeekTableMagic != $magic) {
51
 
52
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"');
53
  return false;
54
 
55
  } else {
116
  }
117
 
118
  if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
119
+ $this->error('PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files');
120
  return false;
121
  }
122
 
125
  $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
126
  foreach ($RequiredFiles as $required_file) {
127
  if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
128
+ $this->error(GETID3_HELPERAPPSDIR.$required_file.' does not exist');
129
  return false;
130
  }
131
  }
139
  $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
140
  }
141
  if (!$shorten_present) {
142
+ $this->error('shorten binary was not found in path or /usr/local/bin');
143
  return false;
144
  }
145
  $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64';
164
 
165
  } else {
166
 
167
+ $this->error('shorten failed to decode DATA chunk to expected location, cannot determine playtime');
168
  return false;
169
 
170
  }
173
 
174
  } else {
175
 
176
+ $this->error('shorten failed to decode file to WAV for parsing');
177
  return false;
178
 
179
  }
lib/getid3/module.audio.tta.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.tta.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_tta extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -32,7 +34,7 @@ class getid3_tta extends getid3_handler
32
  $info['tta']['magic'] = substr($ttaheader, 0, 3);
33
  $magic = 'TTA';
34
  if ($info['tta']['magic'] != $magic) {
35
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"';
36
  unset($info['fileformat']);
37
  unset($info['audio']);
38
  unset($info['tta']);
@@ -90,7 +92,7 @@ class getid3_tta extends getid3_handler
90
  break;
91
 
92
  default:
93
- $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3};
94
  return false;
95
  break;
96
  }
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.tta.php //
17
 
18
  class getid3_tta extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
34
  $info['tta']['magic'] = substr($ttaheader, 0, 3);
35
  $magic = 'TTA';
36
  if ($info['tta']['magic'] != $magic) {
37
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"');
38
  unset($info['fileformat']);
39
  unset($info['audio']);
40
  unset($info['tta']);
92
  break;
93
 
94
  default:
95
+ $this->error('This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3});
96
  return false;
97
  break;
98
  }
lib/getid3/module.audio.voc.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.voc.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_voc extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -27,7 +29,7 @@ class getid3_voc extends getid3_handler
27
 
28
  $magic = 'Creative Voice File';
29
  if (substr($VOCheader, 0, 19) != $magic) {
30
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"';
31
  return false;
32
  }
33
 
@@ -137,7 +139,7 @@ class getid3_voc extends getid3_handler
137
  break;
138
 
139
  default:
140
- $info['warning'][] = 'Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset;
141
  $this->fseek($BlockSize, SEEK_CUR);
142
  break;
143
  }
@@ -164,6 +166,11 @@ class getid3_voc extends getid3_handler
164
  return true;
165
  }
166
 
 
 
 
 
 
167
  public function VOCcompressionTypeLookup($index) {
168
  static $VOCcompressionTypeLookup = array(
169
  0 => '8-bit',
@@ -174,6 +181,11 @@ class getid3_voc extends getid3_handler
174
  return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels');
175
  }
176
 
 
 
 
 
 
177
  public function VOCwFormatLookup($index) {
178
  static $VOCwFormatLookup = array(
179
  0x0000 => '8-bit unsigned PCM',
@@ -188,6 +200,11 @@ class getid3_voc extends getid3_handler
188
  return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
189
  }
190
 
 
 
 
 
 
191
  public function VOCwFormatActualBitsPerSampleLookup($index) {
192
  static $VOCwFormatLookup = array(
193
  0x0000 => 8,
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.voc.php //
17
 
18
  class getid3_voc extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
29
 
30
  $magic = 'Creative Voice File';
31
  if (substr($VOCheader, 0, 19) != $magic) {
32
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"');
33
  return false;
34
  }
35
 
139
  break;
140
 
141
  default:
142
+ $this->warning('Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset);
143
  $this->fseek($BlockSize, SEEK_CUR);
144
  break;
145
  }
166
  return true;
167
  }
168
 
169
+ /**
170
+ * @param int $index
171
+ *
172
+ * @return string
173
+ */
174
  public function VOCcompressionTypeLookup($index) {
175
  static $VOCcompressionTypeLookup = array(
176
  0 => '8-bit',
181
  return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels');
182
  }
183
 
184
+ /**
185
+ * @param int $index
186
+ *
187
+ * @return string|false
188
+ */
189
  public function VOCwFormatLookup($index) {
190
  static $VOCwFormatLookup = array(
191
  0x0000 => '8-bit unsigned PCM',
200
  return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
201
  }
202
 
203
+ /**
204
+ * @param int $index
205
+ *
206
+ * @return int|false
207
+ */
208
  public function VOCwFormatActualBitsPerSampleLookup($index) {
209
  static $VOCwFormatLookup = array(
210
  0x0000 => 8,
lib/getid3/module.audio.vqf.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.vqf.php //
@@ -17,6 +17,9 @@
17
 
18
  class getid3_vqf extends getid3_handler
19
  {
 
 
 
20
  public function Analyze() {
21
  $info = &$this->getid3->info;
22
 
@@ -40,7 +43,7 @@ class getid3_vqf extends getid3_handler
40
  $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
41
  $magic = 'TWIN';
42
  if ($thisfile_vqf_raw['header_tag'] != $magic) {
43
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"';
44
  unset($info['vqf']);
45
  unset($info['fileformat']);
46
  return false;
@@ -65,7 +68,7 @@ class getid3_vqf extends getid3_handler
65
  $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
66
  $chunkoffset += 4;
67
  if ($ChunkSize > ($info['avdataend'] - $this->ftell())) {
68
- $info['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
69
  break;
70
  }
71
  if ($ChunkSize > 0) {
@@ -93,7 +96,7 @@ class getid3_vqf extends getid3_handler
93
  $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000);
94
 
95
  if ($info['audio']['bitrate'] == 0) {
96
- $info['error'][] = 'Corrupt VQF file: bitrate_audio == zero';
97
  return false;
98
  }
99
  break;
@@ -112,7 +115,7 @@ class getid3_vqf extends getid3_handler
112
  break;
113
 
114
  default:
115
- $info['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
116
  break;
117
  }
118
  }
@@ -123,12 +126,12 @@ class getid3_vqf extends getid3_handler
123
  switch ($thisfile_vqf['DSIZ']) {
124
  case 0:
125
  case 1:
126
- $info['warning'][] = 'Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0';
127
  $info['audio']['encoder'] = 'Ahead Nero';
128
  break;
129
 
130
  default:
131
- $info['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'));
132
  break;
133
  }
134
  }
@@ -136,6 +139,11 @@ class getid3_vqf extends getid3_handler
136
  return true;
137
  }
138
 
 
 
 
 
 
139
  public function VQFchannelFrequencyLookup($frequencyid) {
140
  static $VQFchannelFrequencyLookup = array(
141
  11 => 11025,
@@ -145,6 +153,11 @@ class getid3_vqf extends getid3_handler
145
  return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
146
  }
147
 
 
 
 
 
 
148
  public function VQFcommentNiceNameLookup($shortname) {
149
  static $VQFcommentNiceNameLookup = array(
150
  'NAME' => 'title',
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.vqf.php //
17
 
18
  class getid3_vqf extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
43
  $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
44
  $magic = 'TWIN';
45
  if ($thisfile_vqf_raw['header_tag'] != $magic) {
46
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"');
47
  unset($info['vqf']);
48
  unset($info['fileformat']);
49
  return false;
68
  $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
69
  $chunkoffset += 4;
70
  if ($ChunkSize > ($info['avdataend'] - $this->ftell())) {
71
+ $this->error('Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset);
72
  break;
73
  }
74
  if ($ChunkSize > 0) {
96
  $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000);
97
 
98
  if ($info['audio']['bitrate'] == 0) {
99
+ $this->error('Corrupt VQF file: bitrate_audio == zero');
100
  return false;
101
  }
102
  break;
115
  break;
116
 
117
  default:
118
+ $this->warning('Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset);
119
  break;
120
  }
121
  }
126
  switch ($thisfile_vqf['DSIZ']) {
127
  case 0:
128
  case 1:
129
+ $this->warning('Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0');
130
  $info['audio']['encoder'] = 'Ahead Nero';
131
  break;
132
 
133
  default:
134
+ $this->warning('Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA')));
135
  break;
136
  }
137
  }
139
  return true;
140
  }
141
 
142
+ /**
143
+ * @param int $frequencyid
144
+ *
145
+ * @return int
146
+ */
147
  public function VQFchannelFrequencyLookup($frequencyid) {
148
  static $VQFchannelFrequencyLookup = array(
149
  11 => 11025,
153
  return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
154
  }
155
 
156
+ /**
157
+ * @param string $shortname
158
+ *
159
+ * @return string
160
+ */
161
  public function VQFcommentNiceNameLookup($shortname) {
162
  static $VQFcommentNiceNameLookup = array(
163
  'NAME' => 'title',
lib/getid3/module.audio.wavpack.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  /////////////////////////////////////////////////////////////////
3
  /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // See readme.txt for more details //
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.wavpack.php //
@@ -17,7 +17,9 @@
17
 
18
  class getid3_wavpack extends getid3_handler
19
  {
20
-
 
 
21
  public function Analyze() {
22
  $info = &$this->getid3->info;
23
 
@@ -47,7 +49,7 @@ class getid3_wavpack extends getid3_handler
47
 
48
  $magic = 'wvpk';
49
  if ($blockheader_magic != $magic) {
50
- $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"';
51
  switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
52
  case 'wavpack':
53
  case 'wvc':
@@ -86,7 +88,7 @@ class getid3_wavpack extends getid3_handler
86
  $info['wavpack']['blockheader']['size'] = $blockheader_size;
87
 
88
  if ($info['wavpack']['blockheader']['size'] >= 0x100000) {
89
- $info['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$info['wavpack']['blockheader']['size'].'" at offset '.$info['wavpack']['blockheader']['offset'];
1
  <?php
2
+
3
  /////////////////////////////////////////////////////////////////
4
  /// getID3() by James Heinrich <info@getid3.org> //
5
+ // available at https://github.com/JamesHeinrich/getID3 //
6
+ // or https://www.getid3.org //
7
+ // or http://getid3.sourceforge.net //
8
+ // see readme.txt for more details //
 
9
  /////////////////////////////////////////////////////////////////
10
  // //
11
  // module.audio.wavpack.php //
17
 
18
  class getid3_wavpack extends getid3_handler
19
  {
20
+ /**
21
+ * @return bool
22
+ */
23
  public function Analyze() {
24
  $info = &$this->getid3->info;
25
 
49
 
50
  $magic = 'wvpk';
51
  if ($blockheader_magic != $magic) {
52
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"');
53
  switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
54
  case 'wavpack':
55
  case 'wvc':
88
  $info['wavpack']['blockheader']['size'] = $blockheader_size;
89
 
90
  if ($info['wavpack']['blockheader']['size'] >= 0x100000) {
91
+ $this->error('Expecting WavPack block size less than "0x100000", found "'.$info['wavpack']['blockheader']['size'].'" at offset '.$info['