Skip to content

Instantly share code, notes, and snippets.

@tsuchm
Created November 14, 2022 13:18
Show Gist options
  • Save tsuchm/cf7a23d9567c2f5d142cb2d7b59345c7 to your computer and use it in GitHub Desktop.
Save tsuchm/cf7a23d9567c2f5d142cb2d7b59345c7 to your computer and use it in GitHub Desktop.
Script to parse AVCHD playlist format
#!/usr/bin/perl
=head1 OBJECT OF THIS SCRIPT
Panasonic 製デジタルビデオカメラが,SD カードに動画を格納する時,動画データのファイル名は連番になっている.
これを,日付(8桁)-連番というファイル名に変更するために必要な情報を取り出す.
=head1 SYNOPSIS
perl playlist.pl PRIVATE/AVCHD/BDMV/PLAYLIST/00000.MPL
=cut
use Fcntl qw/ :seek /;
use Getopt::Long;
use strict;
use warnings;
use constant { VIDEONUM_POS => 65,
VIDEONUM_LEN => 1,
VIDEONAME_BEG => 70,
VIDEONAME_LEN => 5,
VIDEONAME_SIZE => 98,
HEADLEN_POS => 18,
HEADLEN_LEN => 2,
HEADLEN_OFFSET => 87 + 285 + 1,
VIDEODATE_LEN => 11,
VIDEODATE_SIZE => 66 };
our $VERBOSE;
&GetOptions( 'verbose' => \$VERBOSE );
sub main {
my( $file ) = @_;
printf STDERR "file=%s\n", $file if $VERBOSE;
open( my $fh, '<:raw', $file ) or die;
my $buf;
seek( $fh, VIDEONUM_POS, SEEK_SET );
read( $fh, $buf, VIDEONUM_LEN );
my( $num ) = unpack( 'C', $buf );
printf STDERR "num=%d\n", $num if $VERBOSE;
my @name;
my $pos = VIDEONAME_BEG;
for( my $i = 0; $i < $num; $i++ ){
printf STDERR "pos=%04X\n", $pos if $VERBOSE;
seek( $fh, $pos, SEEK_SET );
read( $fh, $buf, VIDEONAME_LEN );
my( $name ) = unpack( 'a*', $buf );
printf STDERR "name=%s\n", $name if $VERBOSE;
push( @name, $name );
$pos += VIDEONAME_SIZE;
}
seek( $fh, HEADLEN_POS, SEEK_SET );
read( $fh, $buf, HEADLEN_LEN );
$pos = unpack( 'n', $buf );
printf STDERR "len=%d\n", $pos if $VERBOSE;
$pos += HEADLEN_OFFSET;
for( my $i = 0; $i < $num; $i++ ){
printf STDERR "pos=%04X\n", $pos if $VERBOSE;
seek( $fh, $pos, SEEK_SET );
read( $fh, $buf, VIDEODATE_LEN );
my( $type, $date ) = unpack( 'Ca*', $buf );
$pos += VIDEODATE_SIZE;
printf STDERR "type=%d\n", $type if $VERBOSE;
redo unless $type;
printf STDERR "date=%s\n", $date if $VERBOSE;
$date =~ s/ /0/g;
$date =~ s/\.//g;
printf "mv %s.MTS %s-%03d.MTS\n", $name[$i], $date, $i+1;
}
}
for my $f ( @ARGV ){
&main( $f );
}
=head1 DIRECTORY HIERACHY
Panasonic 製デジタルビデオカメラが,SD カードに動画を格納する時のディレクトリ構造の概要は,以下の通り.
PRIVATE/
AVCHD/
AVCHDTN/
BDMV/
INDEX.BDM
MOVIEOBJ.BDM
CLIPINF/
PLAYLIST/
00000.MPL
00001.MPL
00002.MPL
...
STREAM/
00000.MTS
00001.MTS
00002.MTS
...
IISVPL/
MPL という拡張子のファイルがプレイリストであり,MTS という拡張子のファイルが動画データである.
=head1 PLAYLIST FILE FORMAT
動画ファイルを2つ含む場合のプレイリストは,以下のようになっている.
00000000: 4d50 4c53 3031 3030 0000 003a 0000 0108 MPLS0100...:....
00000010: 0000 0138 0000 0000 0000 0000 0000 0000 ...8............
00000040: 0002 0000 0060 3030 3032 384d 3254 5300 .....`00028M2TS.
000000a0: 0590 6a70 6e00 0060 3030 3032 394d 3254 ..jpn..`00029M2T
00000180: 0000 0000 ffff 1e20 1505 2320 2840 0003 ....... ..# (@..
00000190: 0a32 3030 392e 2036 2e32 3800 0000 0000 .2009. 6.28.....
000002a0: 0000 001c 1220 0906 2808 5203 030a 3230 ..... ..(.R...20
000002b0: 3039 2e20 362e 3238 0000 0000 0000 0000 09. 6.28........
000002e0: 0000 0000 001d 1220 0906 2809 2643 030a ....... ..(.&C..
000002f0: 3230 3039 2e20 362e 3238 0000 0000 0000 2009. 6.28......
ヘッダ領域:
0x0000(0): 「MPLS」ファイル種別ヘッダ
0x0004(4): 「0100」おそらく,MPLSフォーマットのバージョン番号
0x000E(14): 0x0108(264) 動画ファイル名領域長(=68+98*ファイル数)
0x0012(18): 0x0138(312) ヘッダ領域長(この値に87を足すと,プレイリスト情報領域のアドレス)
0x0041(65): 0x02 動画リストに含まれる動画ファイル数
動画ファイル名領域 #1(98バイト)
0x0045(69): 0x60 固定
0x0046(70): 「00028」動画ファイル#1のファイル名(拡張子を含まず).
動画ファイル名領域 #2(98バイト)
0x00A7(167): 0x60 固定
0x00A8(168): 「00029」動画ファイル#2のファイル名(拡張子を含まず).
??情報領域
プレイリスト情報領域(285バイト)
0x018F(399): 0x030A 固定
0x0191(401): 「2009. 6.28」おそらく,このプレイリストの作成日.
撮影日領域 #1(66バイト)
0x02AC(684): 0x03 固定
0x02AD(685): 0x00 または 0x0A.0x00 の場合は,この領域をスキップ.
0x02AE(686): 「2009. 6.28」動画ファイルその1の撮影日.
撮影日領域 #2(66バイト)
0x02EE(750): 0x03 固定
0x02EF(751): 0x00 または 0x0A.0x00 の場合は,この領域をスキップ.
0x02F0(752): 「2009. 6.28」動画ファイルその2の撮影日.
動画ファイルを3つ含む場合のプレイリストは,以下のようになっている.
00000000: 4d50 4c53 3031 3030 0000 003a 0000 016a MPLS0100...:...j
00000010: 0000 019a 0000 0000 0000 0000 0000 0000 ................
00000040: 0003 0000 0060 3030 3032 354d 3254 5300 .....`00025M2TS.
000000a0: 0590 6a70 6e00 0060 3030 3032 364d 3254 ..jpn..`00026M2T
00000100: 0000 0590 6a70 6e00 0060 3030 3032 374d ....jpn..`00027M
000001f0: 0003 0a32 3030 392e 2036 2e32 3700 0000 ...2009. 6.27...
00000300: 0000 0000 0019 1220 0906 2709 0414 030a ....... ..'.....
00000310: 3230 3039 2e20 362e 3237 0000 0000 0000 2009. 6.27......
00000350: 030a 3230 3039 2e20 362e 3237 0000 0000 ..2009. 6.27....
00000390: 0550 030a 3230 3039 2e20 362e 3237 0000 .P..2009. 6.27..
ヘッダ領域:
0x0000(0): 「MPLS」ファイル種別ヘッダ
0x0004(4): 「0100」おそらく,MPLSフォーマットのバージョン番号
0x000E(14): 0x016A(362) 動画ファイル名領域長(=68+98*ファイル数)
0x0012(18): 0x019A(410) ヘッダ領域長(この値に87を足すと,プレイリスト情報領域のアドレス)
0x0041(65): 0x02 動画リストに含まれる動画ファイル数
動画ファイル名領域 #1(98バイト)
0x0045(69): 0x60 固定
0x0046(70): 「00025」動画ファイル#1のファイル名(拡張子を含まず).
動画ファイル名領域 #2(98バイト)
0x00A7(167): 0x60 固定
0x00A8(168): 「00026」動画ファイル#2のファイル名(拡張子を含まず).
動画ファイル名領域 #3(98バイト)
0x0109(265): 0x60 固定
0x010A(266): 「00027」動画ファイル#3のファイル名(拡張子を含まず).
プレイリスト情報領域(285バイト)
0x01F1(497): 0x030A 固定
0x01F3(499): 「2009. 6.27」おそらく,このプレイリストの作成日.
撮影日領域 #1(66バイト)
0x030E(782): 0x03 固定
0x030F(783): 0x00 または 0x0A.0x00 の場合は,この領域をスキップ.
0x0310(784): 「2009. 6.27」動画ファイルその1の撮影日.
撮影日領域 #2(66バイト)
0x0350(848): 0x03 固定
0x0351(849): 0x00 または 0x0A.0x00 の場合は,この領域をスキップ.
0x0352(850): 「2009. 6.27」動画ファイルその2の撮影日.
撮影日領域 #3(66バイト)
0x0392(914): 0x030A 固定
0x0393(915): 0x00 または 0x0A.0x00 の場合は,この領域をスキップ.
0x0394(916): 「2009. 6.27」動画ファイルその3の撮影日.
=head1 AUTHOR
TSUCHIYA Masatoshi <tsuchm@gmail.com>
=head1 COPYRIGHT
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment