diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 6bb541dd35..f60fd6bd82 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -3082,9 +3082,32 @@ function wp_read_video_metadata( $file ) { $metadata['audio'] = $data['audio']; } + if ( empty( $metadata['created_timestamp'] ) ) { + $created_timestamp = wp_get_media_creation_timestamp( $data ); + + if ( $created_timestamp !== false ) { + $metadata['created_timestamp'] = $created_timestamp; + } + } + wp_add_id3_tag_data( $metadata, $data ); - return $metadata; + $file_format = isset( $metadata['fileformat'] ) ? $metadata['fileformat'] : null; + + /** + * Filters the array of metadata retrieved from a video. + * + * In core, usually this selection is what is stored. + * More complete data can be parsed from the `$data` parameter. + * + * @since 4.9.0 + * + * @param array $metadata Filtered Video metadata. + * @param string $file Path to video file. + * @param string $file_format File format of video, as analyzed by getID3. + * @param string $data Raw metadata from getID3. + */ + return apply_filters( 'wp_read_video_metadata', $metadata, $file, $file_format, $data ); } /** @@ -3132,6 +3155,55 @@ function wp_read_audio_metadata( $file ) { return $metadata; } +/** + * Parse creation date from media metadata. + * + * The getID3 library doesn't have a standard method for getting creation dates, + * so the location of this data can vary based on the MIME type. + * + * @since 4.9.0 + * + * @link https://github.com/JamesHeinrich/getID3/blob/master/structure.txt + * + * @param array $metadata The metadata returned by getID3::analyze(). + * @return int|bool A UNIX timestamp for the media's creation date if available + * or a boolean FALSE if a timestamp could not be determined. + */ +function wp_get_media_creation_timestamp( $metadata ) { + $creation_date = false; + + if ( empty( $metadata['fileformat'] ) ) { + return $creation_date; + } + + switch ( $metadata['fileformat'] ) { + case 'asf': + if ( isset( $metadata['asf']['file_properties_object']['creation_date_unix'] ) ) { + $creation_date = (int) $metadata['asf']['file_properties_object']['creation_date_unix']; + } + break; + + case 'matroska': + case 'webm': + if ( isset( $metadata['matroska']['comments']['creation_time']['0'] ) ) { + $creation_date = strtotime( $metadata['matroska']['comments']['creation_time']['0'] ); + } + elseif ( isset( $metadata['matroska']['info']['0']['DateUTC_unix'] ) ) { + $creation_date = (int) $metadata['matroska']['info']['0']['DateUTC_unix']; + } + break; + + case 'quicktime': + case 'mp4': + if ( isset( $metadata['quicktime']['moov']['subatoms']['0']['creation_time_unix'] ) ) { + $creation_date = (int) $metadata['quicktime']['moov']['subatoms']['0']['creation_time_unix']; + } + break; + } + + return $creation_date; +} + /** * Encapsulate logic for Attach/Detach actions * diff --git a/tests/phpunit/data/uploads/small-video.mkv b/tests/phpunit/data/uploads/small-video.mkv new file mode 100644 index 0000000000..2b3308441f Binary files /dev/null and b/tests/phpunit/data/uploads/small-video.mkv differ diff --git a/tests/phpunit/data/uploads/small-video.mov b/tests/phpunit/data/uploads/small-video.mov new file mode 100644 index 0000000000..2cfbb86464 Binary files /dev/null and b/tests/phpunit/data/uploads/small-video.mov differ diff --git a/tests/phpunit/data/uploads/small-video.webm b/tests/phpunit/data/uploads/small-video.webm new file mode 100644 index 0000000000..63a974986b Binary files /dev/null and b/tests/phpunit/data/uploads/small-video.webm differ diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index cebc948f25..025b4de841 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -2138,6 +2138,118 @@ EOF; $attachment_id = wp_insert_attachment( $data, '', 0 ); $this->assertSame( 0, $attachment_id ); } + + /** + * @ticket 35218 + */ + function test_wp_get_media_creation_timestamp_video_asf() { + $metadata = array( + 'fileformat' => 'asf', + 'asf' => array( + 'file_properties_object' => array( + 'creation_date_unix' => 123, + ), + ), + ); + + $this->assertEquals( 123, wp_get_media_creation_timestamp( $metadata ) ); + } + + /** + * @ticket 35218 + */ + function test_wp_get_media_creation_timestamp_video_matroska() { + $metadata = array( + 'fileformat' => 'matroska', + 'matroska' => array( + 'comments' => array( + 'creation_time' => array( + '2015-12-24T17:40:09Z' + ), + ), + ), + ); + + $this->assertEquals( 1450978809, wp_get_media_creation_timestamp( $metadata ) ); + } + + /** + * @ticket 35218 + */ + function test_wp_get_media_creation_timestamp_video_quicktime() { + $metadata = array( + 'fileformat' => 'quicktime', + 'quicktime' => array( + 'moov' => array( + 'subatoms' => array( + array( + 'creation_time_unix' => 1450978805, + ), + ), + ), + ), + ); + + $this->assertEquals( 1450978805, wp_get_media_creation_timestamp( $metadata ) ); + } + + /** + * @ticket 35218 + */ + function test_wp_get_media_creation_timestamp_video_webm() { + $metadata = array( + 'fileformat' => 'webm', + 'matroska' => array( + 'info' => array( + array( + 'DateUTC_unix' => 1265680539, + ), + ), + ), + ); + + $this->assertEquals( 1265680539, wp_get_media_creation_timestamp( $metadata ) ); + } + + /** + * @ticket 35218 + */ + function test_wp_read_video_metadata_adds_creation_date_with_quicktime() { + $video = DIR_TESTDATA . '/uploads/small-video.mov'; + $metadata = wp_read_video_metadata( $video ); + + $this->assertEquals( 1269120551, $metadata['created_timestamp'] ); + } + + /** + * @ticket 35218 + */ + function test_wp_read_video_metadata_adds_creation_date_with_mp4() { + $video = DIR_TESTDATA . '/uploads/small-video.mp4'; + $metadata = wp_read_video_metadata( $video ); + + $this->assertEquals( 1269120551, $metadata['created_timestamp'] ); + } + + /** + * @ticket 35218 + */ + function test_wp_read_video_metadata_adds_creation_date_with_mkv() { + $video = DIR_TESTDATA . '/uploads/small-video.mkv'; + $metadata = wp_read_video_metadata( $video ); + + $this->assertEquals( 1269120551, $metadata['created_timestamp'] ); + } + + /** + * @ticket 35218 + */ + function test_wp_read_video_metadata_adds_creation_date_with_webm() { + $video = DIR_TESTDATA . '/uploads/small-video.webm'; + $metadata = wp_read_video_metadata( $video ); + + $this->assertEquals( 1269120551, $metadata['created_timestamp'] ); + } } /**