2
2
/*
3
3
AtomicParsley - nsfile.mm
4
4
5
- AtomicParsley is GPL software; you can freely distribute,
5
+ AtomicParsley is GPL software; you can freely distribute,
6
6
redistribute, modify & use under the terms of the GNU General
7
7
Public License; either version 2 or its successor.
8
8
9
9
AtomicParsley is distributed under the GPL "AS IS", without
10
10
any warranty; without the implied warranty of merchantability
11
11
or fitness for either an expressed or implied particular purpose.
12
12
13
- Please see the included GNU General Public License (GPL) for
13
+ Please see the included GNU General Public License (GPL) for
14
14
your rights and further details; see the file COPYING. If you
15
15
cannot, write to the Free Software Foundation, 59 Temple Place
16
16
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
@@ -26,157 +26,192 @@ Please see the included GNU General Public License (GPL) for
26
26
/* ----------------------
27
27
APar_TestTracksForKind
28
28
29
- By testing which tracks are contained within the file, for Mac OS X we can avoid having to change file extension by instead using Finder.app metadata to signal
30
- the same info as file extension. For each trak atom, find the 'stsd' atom - its ancillary_data will contain the track type that is contained - the info is filled
31
- in as the file was initially parsed in APar_ScanAtoms. Then using Mac OS X Cocoa calls (in AP_NSFile_utils), set the Finder TYPE/CREATOR codes to signal to the
32
- OS/Finder/iTunes that this file is .m4a or .m4v without having to change its extension based on what the tracks actually contain.
33
-
34
- There are 2 issues with this - iTunes requires the Quicktime player type/creator codes for video that has multi-channel audio, and for chapterized video files.
35
- TODO: address these issues.
29
+ By testing which tracks are contained within the file, for Mac OS X we can
30
+ avoid having to change file extension by instead using Finder.app metadata to
31
+ signal the same info as file extension. For each trak atom, find the 'stsd' atom
32
+ - its ancillary_data will contain the track type that is contained - the info is
33
+ filled in as the file was initially parsed in APar_ScanAtoms. Then using Mac OS
34
+ X Cocoa calls (in AP_NSFile_utils), set the Finder TYPE/CREATOR codes to signal
35
+ to the OS/Finder/iTunes that this file is .m4a or .m4v without having to change
36
+ its extension based on what the tracks actually contain.
37
+
38
+ There are 2 issues with this - iTunes requires the Quicktime
39
+ player type/creator codes for video that has multi-channel audio, and for
40
+ chapterized video files.
41
+ TODO: address these issues.
36
42
----------------------*/
37
43
void APar_TestTracksForKind () {
38
- uint8_t total_tracks = 0 ;
39
- uint8_t track_num = 0 ;
40
- AtomicInfo* codec_atom = NULL ; // short codec_atom = 0;
41
-
42
- // With track_num set to 0, it will return the total trak atom into total_tracks here.
43
- APar_FindAtomInTrack (total_tracks, track_num, NULL );
44
-
45
- if (total_tracks > 0 ) {
46
- while (total_tracks > track_num) {
47
- track_num+= 1 ;
48
-
49
- codec_atom = APar_FindAtomInTrack (total_tracks, track_num, " stsd" );
50
- if (codec_atom == NULL ) return ;
51
-
52
- // now test this trak's stsd codec against these 4cc codes:
53
- switch (codec_atom->ancillary_data ) {
54
- // video types
55
- case 0x61766331 : // "avc1"
56
- track_codecs.has_avc1 = true ;
57
- break ;
58
- case 0x6D703476 : // "mp4v"
59
- track_codecs.has_mp4v = true ;
60
- break ;
61
- case 0x64726D69 : // "drmi"
62
- track_codecs.has_drmi = true ;
63
- break ;
64
-
65
- // audio types
66
- case 0x616C6163 : // "alac"
67
- track_codecs.has_alac = true ;
68
- break ;
69
- case 0x6D703461 : // "mp4a"
70
- track_codecs.has_mp4a = true ;
71
- break ;
72
- case 0x64726D73 : // "drms"
73
- track_codecs.has_drms = true ;
74
- break ;
75
-
76
- // chapterized types (audio podcasts or movies)
77
- case 0x74657874 : // "text"
78
- track_codecs.has_timed_text = true ;
79
- break ;
80
- case 0x6A706567 : // "jpeg"
81
- track_codecs.has_timed_jpeg = true ;
82
- break ;
83
-
84
- // either podcast type (audio-only) or timed text subtitles
85
- case 0x74783367 : // "tx3g"
86
- track_codecs.has_timed_tx3g = true ;
87
- break ;
88
-
89
- // other
90
- case 0x6D703473 : // "mp4s"
91
- track_codecs.has_mp4s = true ;
92
- break ;
93
- case 0x72747020 : // "rtp "
94
- track_codecs.has_rtp_hint = true ;
95
- break ;
96
- }
97
- }
98
- }
99
- return ;
100
- }
44
+ uint8_t total_tracks = 0 ;
45
+ uint8_t track_num = 0 ;
46
+ AtomicInfo *codec_atom = NULL ; // short codec_atom = 0;
47
+
48
+ // With track_num set to 0, it will return the total trak atom into
49
+ // total_tracks here.
50
+ APar_FindAtomInTrack (total_tracks, track_num, NULL );
51
+
52
+ if (total_tracks > 0 ) {
53
+ while (total_tracks > track_num) {
54
+ track_num += 1 ;
55
+
56
+ codec_atom = APar_FindAtomInTrack (total_tracks, track_num, " stsd" );
57
+ if (codec_atom == NULL )
58
+ return ;
59
+
60
+ // now test this trak's stsd codec against these 4cc codes:
61
+ switch (codec_atom->ancillary_data ) {
62
+ // video types
63
+ case 0x61766331 : // "avc1"
64
+ track_codecs.has_avc1 = true ;
65
+ break ;
66
+ case 0x6D703476 : // "mp4v"
67
+ track_codecs.has_mp4v = true ;
68
+ break ;
69
+ case 0x64726D69 : // "drmi"
70
+ track_codecs.has_drmi = true ;
71
+ break ;
72
+
73
+ // audio types
74
+ case 0x616C6163 : // "alac"
75
+ track_codecs.has_alac = true ;
76
+ break ;
77
+ case 0x6D703461 : // "mp4a"
78
+ track_codecs.has_mp4a = true ;
79
+ break ;
80
+ case 0x64726D73 : // "drms"
81
+ track_codecs.has_drms = true ;
82
+ break ;
101
83
84
+ // chapterized types (audio podcasts or movies)
85
+ case 0x74657874 : // "text"
86
+ track_codecs.has_timed_text = true ;
87
+ break ;
88
+ case 0x6A706567 : // "jpeg"
89
+ track_codecs.has_timed_jpeg = true ;
90
+ break ;
102
91
103
- // TODO: there is a problem with this code seen in: "5.1channel audio-orig.mp4"
104
- // it makes no difference what the file contains, iTunes won't see any (ANY) metadata if its hook/'M4A '.
105
- // in fact, iTunes won't play the file at all
106
- // changing the exact file (with all kinds of metadata) to TVOD/mpg4 - iTunes can play it fine, but doesn't fetch any metadata
92
+ // either podcast type (audio-only) or timed text subtitles
93
+ case 0x74783367 : // "tx3g"
94
+ track_codecs.has_timed_tx3g = true ;
95
+ break ;
96
+
97
+ // other
98
+ case 0x6D703473 : // "mp4s"
99
+ track_codecs.has_mp4s = true ;
100
+ break ;
101
+ case 0x72747020 : // "rtp "
102
+ track_codecs.has_rtp_hint = true ;
103
+ break ;
104
+ }
105
+ }
106
+ }
107
+ return ;
108
+ }
109
+
110
+ // TODO: there is a problem with this code seen in: "5.1channel audio-orig.mp4"
111
+ // it makes no difference what the file contains, iTunes won't see any (ANY)
112
+ // metadata if its hook/'M4A '. in fact, iTunes won't play the file at all
113
+ // changing the exact file (with all kinds of metadata) to TVOD/mpg4 - iTunes
114
+ // can play it fine, but doesn't fetch any metadata
107
115
//
108
- // it might be beneficial to eval for channels and if its audio only & multichannel to NOT change the TYPE/creator codes
109
-
110
- uint32_t APar_4CC_CreatorCode (const char * filepath, uint32_t new_type_code) {
111
- uint32_t return_value = 0 ;
112
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc ] init ];
113
-
114
- NSString *inFile = [NSString stringWithUTF8String: filepath];
115
-
116
- if (new_type_code) {
117
- NSNumber * creator_code = [NSNumber numberWithUnsignedLong: ' hook' ];
118
- NSNumber * type_code = [NSNumber numberWithUnsignedLong: new_type_code];
119
- NSDictionary * output_attributes = [NSDictionary dictionaryWithObjectsAndKeys: creator_code, NSFileHFSCreatorCode ,
120
- type_code, NSFileHFSTypeCode , nil ];
121
-
122
- if (![[NSFileManager defaultManager ] changeFileAttributes: output_attributes atPath: inFile]) {
123
- NSLog (@" AtomicParsley error: setting type and creator code on %@ " , inFile);
124
- }
125
-
126
- } else {
127
- NSDictionary * file_attributes = [[NSFileManager defaultManager ] fileAttributesAtPath: inFile traverseLink: YES ];
128
- return_value = [[file_attributes objectForKey: NSFileHFSTypeCode ] unsignedLongValue ];
129
-
130
- // NSLog(@"code: %@\n", [file_attributes objectForKey:NSFileHFSTypeCode] );
131
- }
132
-
133
- [pool release ];
134
-
135
- return return_value;
116
+ // it might be beneficial to eval for channels and if its audio only &
117
+ // multichannel to NOT change the TYPE/creator codes
118
+
119
+ uint32_t APar_4CC_CreatorCode (const char *filepath, uint32_t new_type_code) {
120
+ uint32_t return_value = 0 ;
121
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc ] init ];
122
+
123
+ NSString *inFile = [NSString stringWithUTF8String: filepath];
124
+
125
+ if (new_type_code) {
126
+ NSNumber *creator_code = [NSNumber numberWithUnsignedLong: ' hook' ];
127
+ NSNumber *type_code = [NSNumber numberWithUnsignedLong: new_type_code];
128
+ NSDictionary *output_attributes =
129
+ [NSDictionary dictionaryWithObjectsAndKeys: creator_code,
130
+ NSFileHFSCreatorCode ,
131
+ type_code,
132
+ NSFileHFSTypeCode ,
133
+ nil ];
134
+
135
+ if (![[NSFileManager defaultManager ] changeFileAttributes: output_attributes
136
+ atPath: inFile]) {
137
+ NSLog (@" AtomicParsley error: setting type and creator code on %@ " ,
138
+ inFile);
139
+ }
140
+
141
+ } else {
142
+ NSDictionary *file_attributes =
143
+ [[NSFileManager defaultManager ] fileAttributesAtPath: inFile
144
+ traverseLink: YES ];
145
+ return_value =
146
+ [[file_attributes objectForKey: NSFileHFSTypeCode ] unsignedLongValue ];
147
+
148
+ // NSLog(@"code: %@\n", [file_attributes objectForKey:NSFileHFSTypeCode] );
149
+ }
150
+
151
+ [pool release ];
152
+
153
+ return return_value;
136
154
}
137
155
138
- // there is a scenario that is as of now unsupported (or botched, depending if you use the feature), although it would be easy to implement. To make a file bookmarkable, the TYPE code is set to 'M4B ' - which can be *also* done by changing the extension to ".m4b". However, due to the way that the file is tested here, a ".mp4" with 'M4B ' type code will get changed into a normal audio file (not-bookmarkable).
139
-
140
- void APar_SupplySelectiveTypeCreatorCodes (const char *inputPath, const char *outputPath, uint8_t forced_type_code) {
141
- if (forced_type_code != NO_TYPE_FORCING) {
142
- if (forced_type_code == FORCE_M4B_TYPE) {
143
- APar_4CC_CreatorCode (outputPath, ' M4B ' );
144
- }
145
- return ;
146
- }
147
-
148
- const char * input_suffix = strrchr (inputPath, ' .' );
149
- // user-defined output paths may have the original file as ".m4a" & show up fine when output to ".m4a"
150
- // output to ".mp4" and it becomes a generic (sans TYPE/CREATOR) file that defaults to Quicktime Player
151
- const char * output_suffix = strrchr (outputPath, ' .' );
152
-
153
- char * typecode = (char *)malloc ( sizeof (char )* 4 );
154
- memset (typecode, 0 , sizeof (char )*4 );
155
-
156
- uint32_t type_code = APar_4CC_CreatorCode (inputPath, 0 );
157
-
158
- UInt32_TO_String4 (type_code, typecode);
159
-
160
- // fprintf(stdout, "%s - %s\n", typecode, input_suffix);
161
- APar_TestTracksForKind ();
162
-
163
- if (strncasecmp (input_suffix, " .mp4" , 4 ) == 0 || strncasecmp (output_suffix, " .mp4" , 4 ) == 0 ) { // only work on the generic .mp4 extension
164
- if (track_codecs.has_avc1 || track_codecs.has_mp4v || track_codecs.has_drmi ) {
165
- type_code = APar_4CC_CreatorCode (outputPath, ' M4V ' );
166
-
167
- // for a podcast an audio track with either a text, jpeg or url track is required, otherwise it will fall through to generic m4a;
168
- // files that are already .m4b or 'M4B ' don't even enter into this situation, so they are safe
169
- // if the file had video with subtitles (tx3g), then it would get taken care of above in the video section - unsupported by QT currently
170
- } else if (track_codecs.has_mp4a && (track_codecs.has_timed_text || track_codecs.has_timed_jpeg || track_codecs.has_timed_tx3g ) ) {
171
- type_code = APar_4CC_CreatorCode (outputPath, ' M4B ' );
172
-
173
- // default to audio; technically so would a drms iTMS drm audio file with ".mp4". But that would also mean it was renamed. They should be 'M4P '
174
- } else {
175
- type_code = APar_4CC_CreatorCode (outputPath, ' M4A ' );
176
- }
177
- } else if (track_codecs.has_avc1 || track_codecs.has_mp4v || track_codecs.has_drmi ) {
178
- type_code = APar_4CC_CreatorCode (outputPath, ' M4V ' );
179
- }
180
-
181
- return ;
156
+ // there is a scenario that is as of now unsupported (or botched, depending if
157
+ // you use the feature), although it would be easy to implement. To make a file
158
+ // bookmarkable, the TYPE code is set to 'M4B ' - which can be *also* done by
159
+ // changing the extension to ".m4b". However, due to the way that the file is
160
+ // tested here, a ".mp4" with 'M4B ' type code will get changed into a normal
161
+ // audio file (not-bookmarkable).
162
+
163
+ void APar_SupplySelectiveTypeCreatorCodes (const char *inputPath,
164
+ const char *outputPath,
165
+ uint8_t forced_type_code) {
166
+ if (forced_type_code != NO_TYPE_FORCING) {
167
+ if (forced_type_code == FORCE_M4B_TYPE) {
168
+ APar_4CC_CreatorCode (outputPath, ' M4B ' );
169
+ }
170
+ return ;
171
+ }
172
+
173
+ const char *input_suffix = strrchr (inputPath, ' .' );
174
+ // user-defined output paths may have the original file as ".m4a" & show up
175
+ // fine when output to ".m4a" output to ".mp4" and it becomes a generic (sans
176
+ // TYPE/CREATOR) file that defaults to Quicktime Player
177
+ const char *output_suffix = strrchr (outputPath, ' .' );
178
+
179
+ char *typecode = (char *)malloc (sizeof (char ) * 4 );
180
+ memset (typecode, 0 , sizeof (char ) * 4 );
181
+
182
+ uint32_t type_code = APar_4CC_CreatorCode (inputPath, 0 );
183
+
184
+ UInt32_TO_String4 (type_code, typecode);
185
+
186
+ // fprintf(stdout, "%s - %s\n", typecode, input_suffix);
187
+ APar_TestTracksForKind ();
188
+
189
+ if (strncasecmp (input_suffix, " .mp4" , 4 ) == 0 ||
190
+ strncasecmp (output_suffix, " .mp4" , 4 ) ==
191
+ 0 ) { // only work on the generic .mp4 extension
192
+ if (track_codecs.has_avc1 || track_codecs.has_mp4v ||
193
+ track_codecs.has_drmi ) {
194
+ type_code = APar_4CC_CreatorCode (outputPath, ' M4V ' );
195
+
196
+ // for a podcast an audio track with either a text, jpeg or url track is
197
+ // required, otherwise it will fall through to generic m4a; files that are
198
+ // already .m4b or 'M4B ' don't even enter into this situation, so they
199
+ // are safe if the file had video with subtitles (tx3g), then it would get
200
+ // taken care of above in the video section - unsupported by QT currently
201
+ } else if (track_codecs.has_mp4a &&
202
+ (track_codecs.has_timed_text || track_codecs.has_timed_jpeg ||
203
+ track_codecs.has_timed_tx3g )) {
204
+ type_code = APar_4CC_CreatorCode (outputPath, ' M4B ' );
205
+
206
+ // default to audio; technically so would a drms iTMS drm audio file with
207
+ // ".mp4". But that would also mean it was renamed. They should be 'M4P '
208
+ } else {
209
+ type_code = APar_4CC_CreatorCode (outputPath, ' M4A ' );
210
+ }
211
+ } else if (track_codecs.has_avc1 || track_codecs.has_mp4v ||
212
+ track_codecs.has_drmi ) {
213
+ type_code = APar_4CC_CreatorCode (outputPath, ' M4V ' );
214
+ }
215
+
216
+ return ;
182
217
}
0 commit comments