1 | /* MiniDLNA media server |
---|
2 | * Copyright (C) 2008-2009 Justin Maggard |
---|
3 | * |
---|
4 | * This file is part of MiniDLNA. |
---|
5 | * |
---|
6 | * MiniDLNA is free software; you can redistribute it and/or modify |
---|
7 | * it under the terms of the GNU General Public License version 2 as |
---|
8 | * published by the Free Software Foundation. |
---|
9 | * |
---|
10 | * MiniDLNA is distributed in the hope that it will be useful, |
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | * GNU General Public License for more details. |
---|
14 | * |
---|
15 | * You should have received a copy of the GNU General Public License |
---|
16 | * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>. |
---|
17 | */ |
---|
18 | #include <stdio.h> |
---|
19 | #include <ctype.h> |
---|
20 | #include <string.h> |
---|
21 | #include <stdlib.h> |
---|
22 | #include <sys/stat.h> |
---|
23 | |
---|
24 | #include <unistd.h> |
---|
25 | #include <sys/types.h> |
---|
26 | #include <sys/stat.h> |
---|
27 | #include <fcntl.h> |
---|
28 | |
---|
29 | #include <libexif/exif-loader.h> |
---|
30 | #include "image_utils.h" |
---|
31 | #include <jpeglib.h> |
---|
32 | #include <setjmp.h> |
---|
33 | #include <avutil.h> |
---|
34 | #include <avcodec.h> |
---|
35 | #include <avformat.h> |
---|
36 | #include "tagutils/tagutils.h" |
---|
37 | |
---|
38 | #include "upnpglobalvars.h" |
---|
39 | #include "upnpreplyparse.h" |
---|
40 | #include "metadata.h" |
---|
41 | #include "albumart.h" |
---|
42 | #include "utils.h" |
---|
43 | #include "sql.h" |
---|
44 | #include "log.h" |
---|
45 | |
---|
46 | #ifndef FF_PROFILE_H264_BASELINE |
---|
47 | #define FF_PROFILE_H264_BASELINE 66 |
---|
48 | #endif |
---|
49 | #ifndef FF_PROFILE_H264_MAIN |
---|
50 | #define FF_PROFILE_H264_MAIN 77 |
---|
51 | #endif |
---|
52 | #ifndef FF_PROFILE_H264_HIGH |
---|
53 | #define FF_PROFILE_H264_HIGH 100 |
---|
54 | #endif |
---|
55 | #define FF_PROFILE_SKIP -100 |
---|
56 | |
---|
57 | #if LIBAVCODEC_VERSION_MAJOR < 53 |
---|
58 | #define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO |
---|
59 | #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO |
---|
60 | #endif |
---|
61 | |
---|
62 | #define FLAG_TITLE 0x00000001 |
---|
63 | #define FLAG_ARTIST 0x00000002 |
---|
64 | #define FLAG_ALBUM 0x00000004 |
---|
65 | #define FLAG_GENRE 0x00000008 |
---|
66 | #define FLAG_COMMENT 0x00000010 |
---|
67 | #define FLAG_CREATOR 0x00000020 |
---|
68 | #define FLAG_DATE 0x00000040 |
---|
69 | #define FLAG_DLNA_PN 0x00000080 |
---|
70 | #define FLAG_MIME 0x00000100 |
---|
71 | #define FLAG_DURATION 0x00000200 |
---|
72 | #define FLAG_RESOLUTION 0x00000400 |
---|
73 | #define FLAG_BITRATE 0x00000800 |
---|
74 | #define FLAG_FREQUENCY 0x00001000 |
---|
75 | #define FLAG_BPS 0x00002000 |
---|
76 | #define FLAG_CHANNELS 0x00004000 |
---|
77 | |
---|
78 | /* Audio profile flags */ |
---|
79 | enum audio_profiles { |
---|
80 | PROFILE_AUDIO_UNKNOWN, |
---|
81 | PROFILE_AUDIO_MP3, |
---|
82 | PROFILE_AUDIO_AC3, |
---|
83 | PROFILE_AUDIO_WMA_BASE, |
---|
84 | PROFILE_AUDIO_WMA_FULL, |
---|
85 | PROFILE_AUDIO_WMA_PRO, |
---|
86 | PROFILE_AUDIO_MP2, |
---|
87 | PROFILE_AUDIO_PCM, |
---|
88 | PROFILE_AUDIO_AAC, |
---|
89 | PROFILE_AUDIO_AAC_MULT5, |
---|
90 | PROFILE_AUDIO_AMR |
---|
91 | }; |
---|
92 | |
---|
93 | /* This function shamelessly copied from libdlna */ |
---|
94 | #define MPEG_TS_SYNC_CODE 0x47 |
---|
95 | #define MPEG_TS_PACKET_LENGTH 188 |
---|
96 | #define MPEG_TS_PACKET_LENGTH_DLNA 192 /* prepends 4 bytes to TS packet */ |
---|
97 | int |
---|
98 | dlna_timestamp_is_present(const char * filename, int * raw_packet_size) |
---|
99 | { |
---|
100 | unsigned char buffer[3*MPEG_TS_PACKET_LENGTH_DLNA]; |
---|
101 | int fd, i; |
---|
102 | |
---|
103 | /* read file header */ |
---|
104 | fd = open(filename, O_RDONLY); |
---|
105 | read(fd, buffer, MPEG_TS_PACKET_LENGTH_DLNA*3); |
---|
106 | close(fd); |
---|
107 | for( i=0; i < MPEG_TS_PACKET_LENGTH_DLNA; i++ ) |
---|
108 | { |
---|
109 | if( buffer[i] == MPEG_TS_SYNC_CODE ) |
---|
110 | { |
---|
111 | if (buffer[i + MPEG_TS_PACKET_LENGTH_DLNA] == MPEG_TS_SYNC_CODE && |
---|
112 | buffer[i + MPEG_TS_PACKET_LENGTH_DLNA*2] == MPEG_TS_SYNC_CODE) |
---|
113 | { |
---|
114 | *raw_packet_size = MPEG_TS_PACKET_LENGTH_DLNA; |
---|
115 | if (buffer[i+MPEG_TS_PACKET_LENGTH] == 0x00 && |
---|
116 | buffer[i+MPEG_TS_PACKET_LENGTH+1] == 0x00 && |
---|
117 | buffer[i+MPEG_TS_PACKET_LENGTH+2] == 0x00 && |
---|
118 | buffer[i+MPEG_TS_PACKET_LENGTH+3] == 0x00) |
---|
119 | return 0; |
---|
120 | else |
---|
121 | return 1; |
---|
122 | } else if (buffer[i + MPEG_TS_PACKET_LENGTH] == MPEG_TS_SYNC_CODE && |
---|
123 | buffer[i + MPEG_TS_PACKET_LENGTH*2] == MPEG_TS_SYNC_CODE) { |
---|
124 | *raw_packet_size = MPEG_TS_PACKET_LENGTH; |
---|
125 | return 0; |
---|
126 | } |
---|
127 | } |
---|
128 | } |
---|
129 | *raw_packet_size = 0; |
---|
130 | return 0; |
---|
131 | } |
---|
132 | |
---|
133 | #ifdef TIVO_SUPPORT |
---|
134 | int |
---|
135 | is_tivo_file(const char * path) |
---|
136 | { |
---|
137 | unsigned char buf[5]; |
---|
138 | unsigned char hdr[5] = { 'T','i','V','o','\0' }; |
---|
139 | int fd; |
---|
140 | |
---|
141 | /* read file header */ |
---|
142 | fd = open(path, O_RDONLY); |
---|
143 | read(fd, buf, 5); |
---|
144 | close(fd); |
---|
145 | |
---|
146 | return( !memcmp(buf, hdr, 5) ); |
---|
147 | } |
---|
148 | #endif |
---|
149 | |
---|
150 | void |
---|
151 | check_for_captions(const char * path, sqlite_int64 detailID) |
---|
152 | { |
---|
153 | char *file = malloc(PATH_MAX); |
---|
154 | char *id = NULL; |
---|
155 | |
---|
156 | sprintf(file, "%s", path); |
---|
157 | strip_ext(file); |
---|
158 | |
---|
159 | /* If we weren't given a detail ID, look for one. */ |
---|
160 | if( !detailID ) |
---|
161 | { |
---|
162 | id = sql_get_text_field(db, "SELECT ID from DETAILS where PATH glob '%q.*'" |
---|
163 | " and MIME glob 'video/*' limit 1", file); |
---|
164 | if( id ) |
---|
165 | { |
---|
166 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, "New file %s looks like a caption file.\n", path); |
---|
167 | detailID = strtoll(id, NULL, 10); |
---|
168 | } |
---|
169 | else |
---|
170 | { |
---|
171 | //DPRINTF(E_DEBUG, L_METADATA, "No file found for caption %s.\n", path); |
---|
172 | goto no_source_video; |
---|
173 | } |
---|
174 | } |
---|
175 | |
---|
176 | strcat(file, ".srt"); |
---|
177 | if( access(file, R_OK) == 0 ) |
---|
178 | { |
---|
179 | sql_exec(db, "INSERT into CAPTIONS" |
---|
180 | " (ID, PATH) " |
---|
181 | "VALUES" |
---|
182 | " (%lld, %Q)", detailID, file); |
---|
183 | } |
---|
184 | no_source_video: |
---|
185 | if( id ) |
---|
186 | sqlite3_free(id); |
---|
187 | free(file); |
---|
188 | } |
---|
189 | |
---|
190 | void |
---|
191 | parse_nfo(const char * path, metadata_t * m) |
---|
192 | { |
---|
193 | FILE *nfo; |
---|
194 | char buf[65536]; |
---|
195 | struct NameValueParserData xml; |
---|
196 | struct stat file; |
---|
197 | size_t nread; |
---|
198 | char *val, *val2; |
---|
199 | |
---|
200 | if( stat(path, &file) != 0 || |
---|
201 | file.st_size > 65536 ) |
---|
202 | { |
---|
203 | DPRINTF(E_INFO, L_METADATA, "Not parsing very large .nfo file %s\n", path); |
---|
204 | return; |
---|
205 | } |
---|
206 | DPRINTF(E_DEBUG, L_METADATA, "Parsing .nfo file: %s\n", path); |
---|
207 | nfo = fopen(path, "r"); |
---|
208 | if( !nfo ) |
---|
209 | return; |
---|
210 | nread = fread(&buf, 1, sizeof(buf), nfo); |
---|
211 | |
---|
212 | ParseNameValue(buf, nread, &xml); |
---|
213 | |
---|
214 | //printf("\ttype: %s\n", GetValueFromNameValueList(&xml, "rootElement")); |
---|
215 | val = GetValueFromNameValueList(&xml, "title"); |
---|
216 | if( val ) |
---|
217 | { |
---|
218 | val2 = GetValueFromNameValueList(&xml, "episodetitle"); |
---|
219 | if( val2 ) |
---|
220 | asprintf(&m->title, "%s - %s", val, val2); |
---|
221 | else |
---|
222 | m->title = strdup(val); |
---|
223 | } |
---|
224 | |
---|
225 | val = GetValueFromNameValueList(&xml, "plot"); |
---|
226 | if( val ) |
---|
227 | m->comment = strdup(val); |
---|
228 | |
---|
229 | val = GetValueFromNameValueList(&xml, "capturedate"); |
---|
230 | if( val ) |
---|
231 | m->date = strdup(val); |
---|
232 | |
---|
233 | val = GetValueFromNameValueList(&xml, "genre"); |
---|
234 | if( val ) |
---|
235 | m->genre = strdup(val); |
---|
236 | |
---|
237 | ClearNameValueList(&xml); |
---|
238 | fclose(nfo); |
---|
239 | } |
---|
240 | |
---|
241 | void |
---|
242 | free_metadata(metadata_t * m, uint32_t flags) |
---|
243 | { |
---|
244 | if( m->title && (flags & FLAG_TITLE) ) |
---|
245 | free(m->title); |
---|
246 | if( m->artist && (flags & FLAG_ARTIST) ) |
---|
247 | free(m->artist); |
---|
248 | if( m->album && (flags & FLAG_ALBUM) ) |
---|
249 | free(m->album); |
---|
250 | if( m->genre && (flags & FLAG_GENRE) ) |
---|
251 | free(m->genre); |
---|
252 | if( m->creator && (flags & FLAG_CREATOR) ) |
---|
253 | free(m->creator); |
---|
254 | if( m->date && (flags & FLAG_DATE) ) |
---|
255 | free(m->date); |
---|
256 | if( m->comment && (flags & FLAG_COMMENT) ) |
---|
257 | free(m->comment); |
---|
258 | if( m->dlna_pn && (flags & FLAG_DLNA_PN) ) |
---|
259 | free(m->dlna_pn); |
---|
260 | if( m->mime && (flags & FLAG_MIME) ) |
---|
261 | free(m->mime); |
---|
262 | if( m->duration && (flags & FLAG_DURATION) ) |
---|
263 | free(m->duration); |
---|
264 | if( m->resolution && (flags & FLAG_RESOLUTION) ) |
---|
265 | free(m->resolution); |
---|
266 | if( m->bitrate && (flags & FLAG_BITRATE) ) |
---|
267 | free(m->bitrate); |
---|
268 | if( m->frequency && (flags & FLAG_FREQUENCY) ) |
---|
269 | free(m->frequency); |
---|
270 | if( m->bps && (flags & FLAG_BPS) ) |
---|
271 | free(m->bps); |
---|
272 | if( m->channels && (flags & FLAG_CHANNELS) ) |
---|
273 | free(m->channels); |
---|
274 | } |
---|
275 | |
---|
276 | sqlite_int64 |
---|
277 | GetFolderMetadata(const char * name, const char * path, const char * artist, const char * genre, sqlite3_int64 album_art) |
---|
278 | { |
---|
279 | int ret; |
---|
280 | |
---|
281 | ret = sql_exec(db, "INSERT into DETAILS" |
---|
282 | " (TITLE, PATH, CREATOR, ARTIST, GENRE, ALBUM_ART) " |
---|
283 | "VALUES" |
---|
284 | " ('%q', %Q, %Q, %Q, %Q, %lld);", |
---|
285 | name, path, artist, artist, genre, album_art); |
---|
286 | if( ret != SQLITE_OK ) |
---|
287 | ret = 0; |
---|
288 | else |
---|
289 | ret = sqlite3_last_insert_rowid(db); |
---|
290 | |
---|
291 | return ret; |
---|
292 | } |
---|
293 | |
---|
294 | sqlite_int64 |
---|
295 | GetAudioMetadata(const char * path, char * name) |
---|
296 | { |
---|
297 | char type[4]; |
---|
298 | static char lang[6] = { '\0' }; |
---|
299 | struct stat file; |
---|
300 | sqlite_int64 ret; |
---|
301 | char *esc_tag; |
---|
302 | int i; |
---|
303 | sqlite_int64 album_art = 0; |
---|
304 | struct song_metadata song; |
---|
305 | metadata_t m; |
---|
306 | uint32_t free_flags = FLAG_MIME|FLAG_DURATION|FLAG_DLNA_PN|FLAG_DATE; |
---|
307 | memset(&m, '\0', sizeof(metadata_t)); |
---|
308 | |
---|
309 | if ( stat(path, &file) != 0 ) |
---|
310 | return 0; |
---|
311 | strip_ext(name); |
---|
312 | |
---|
313 | if( ends_with(path, ".mp3") ) |
---|
314 | { |
---|
315 | strcpy(type, "mp3"); |
---|
316 | m.mime = strdup("audio/mpeg"); |
---|
317 | } |
---|
318 | else if( ends_with(path, ".m4a") || ends_with(path, ".mp4") || |
---|
319 | ends_with(path, ".aac") || ends_with(path, ".m4p") ) |
---|
320 | { |
---|
321 | strcpy(type, "aac"); |
---|
322 | m.mime = strdup("audio/mp4"); |
---|
323 | } |
---|
324 | else if( ends_with(path, ".3gp") ) |
---|
325 | { |
---|
326 | strcpy(type, "aac"); |
---|
327 | m.mime = strdup("audio/3gpp"); |
---|
328 | } |
---|
329 | else if( ends_with(path, ".wma") || ends_with(path, ".asf") ) |
---|
330 | { |
---|
331 | strcpy(type, "asf"); |
---|
332 | m.mime = strdup("audio/x-ms-wma"); |
---|
333 | } |
---|
334 | else if( ends_with(path, ".flac") || ends_with(path, ".fla") || ends_with(path, ".flc") ) |
---|
335 | { |
---|
336 | strcpy(type, "flc"); |
---|
337 | m.mime = strdup("audio/x-flac"); |
---|
338 | } |
---|
339 | else if( ends_with(path, ".wav") ) |
---|
340 | { |
---|
341 | strcpy(type, "wav"); |
---|
342 | m.mime = strdup("audio/x-wav"); |
---|
343 | } |
---|
344 | else if( ends_with(path, ".ogg") || ends_with(path, ".oga") ) |
---|
345 | { |
---|
346 | strcpy(type, "ogg"); |
---|
347 | m.mime = strdup("audio/ogg"); |
---|
348 | } |
---|
349 | else if( ends_with(path, ".pcm") ) |
---|
350 | { |
---|
351 | strcpy(type, "pcm"); |
---|
352 | m.mime = strdup("audio/L16"); |
---|
353 | } |
---|
354 | else |
---|
355 | { |
---|
356 | DPRINTF(E_WARN, L_GENERAL, "Unhandled file extension on %s\n", path); |
---|
357 | return 0; |
---|
358 | } |
---|
359 | |
---|
360 | if( !(*lang) ) |
---|
361 | { |
---|
362 | if( !getenv("LANG") ) |
---|
363 | strcpy(lang, "en_US"); |
---|
364 | else |
---|
365 | strncpy(lang, getenv("LANG"), 5); |
---|
366 | lang[5] = '\0'; |
---|
367 | } |
---|
368 | |
---|
369 | if( readtags((char *)path, &song, &file, lang, type) != 0 ) |
---|
370 | { |
---|
371 | DPRINTF(E_WARN, L_GENERAL, "Cannot extract tags from %s!\n", path); |
---|
372 | freetags(&song); |
---|
373 | free_metadata(&m, free_flags); |
---|
374 | return 0; |
---|
375 | } |
---|
376 | |
---|
377 | if( song.dlna_pn ) |
---|
378 | asprintf(&m.dlna_pn, "%s;DLNA.ORG_OP=01;DLNA.ORG_CI=0", song.dlna_pn); |
---|
379 | if( song.year ) |
---|
380 | asprintf(&m.date, "%04d-01-01", song.year); |
---|
381 | asprintf(&m.duration, "%d:%02d:%02d.%03d", |
---|
382 | (song.song_length/3600000), |
---|
383 | (song.song_length/60000%60), |
---|
384 | (song.song_length/1000%60), |
---|
385 | (song.song_length%1000)); |
---|
386 | if( song.title && *song.title ) |
---|
387 | { |
---|
388 | m.title = trim(song.title); |
---|
389 | if( (esc_tag = escape_tag(m.title, 0)) ) |
---|
390 | { |
---|
391 | free_flags |= FLAG_TITLE; |
---|
392 | m.title = esc_tag; |
---|
393 | } |
---|
394 | } |
---|
395 | else |
---|
396 | { |
---|
397 | m.title = name; |
---|
398 | } |
---|
399 | for( i=ROLE_START; i<N_ROLE; i++ ) |
---|
400 | { |
---|
401 | if( song.contributor[i] && *song.contributor[i] ) |
---|
402 | { |
---|
403 | m.creator = trim(song.contributor[i]); |
---|
404 | if( strlen(m.creator) > 48 ) |
---|
405 | { |
---|
406 | m.creator = strdup("Various Artists"); |
---|
407 | free_flags |= FLAG_CREATOR; |
---|
408 | } |
---|
409 | else if( (esc_tag = escape_tag(m.creator, 0)) ) |
---|
410 | { |
---|
411 | m.creator = esc_tag; |
---|
412 | free_flags |= FLAG_CREATOR; |
---|
413 | } |
---|
414 | m.artist = m.creator; |
---|
415 | break; |
---|
416 | } |
---|
417 | } |
---|
418 | /* If there is a band associated with the album, use it for virtual containers. */ |
---|
419 | if( (i != ROLE_BAND) && (i != ROLE_ALBUMARTIST) ) |
---|
420 | { |
---|
421 | if( song.contributor[ROLE_BAND] && *song.contributor[ROLE_BAND] ) |
---|
422 | { |
---|
423 | i = ROLE_BAND; |
---|
424 | m.artist = trim(song.contributor[i]); |
---|
425 | if( strlen(m.artist) > 48 ) |
---|
426 | { |
---|
427 | m.artist = strdup("Various Artists"); |
---|
428 | free_flags |= FLAG_ARTIST; |
---|
429 | } |
---|
430 | else if( (esc_tag = escape_tag(m.artist, 0)) ) |
---|
431 | { |
---|
432 | m.artist = esc_tag; |
---|
433 | free_flags |= FLAG_ARTIST; |
---|
434 | } |
---|
435 | } |
---|
436 | } |
---|
437 | if( song.album && *song.album ) |
---|
438 | { |
---|
439 | m.album = trim(song.album); |
---|
440 | if( (esc_tag = escape_tag(m.album, 0)) ) |
---|
441 | { |
---|
442 | free_flags |= FLAG_ALBUM; |
---|
443 | m.album = esc_tag; |
---|
444 | } |
---|
445 | } |
---|
446 | if( song.genre && *song.genre ) |
---|
447 | { |
---|
448 | m.genre = trim(song.genre); |
---|
449 | if( (esc_tag = escape_tag(m.genre, 0)) ) |
---|
450 | { |
---|
451 | free_flags |= FLAG_GENRE; |
---|
452 | m.genre = esc_tag; |
---|
453 | } |
---|
454 | } |
---|
455 | if( song.comment && *song.comment ) |
---|
456 | { |
---|
457 | m.comment = trim(song.comment); |
---|
458 | if( (esc_tag = escape_tag(m.comment, 0)) ) |
---|
459 | { |
---|
460 | free_flags |= FLAG_COMMENT; |
---|
461 | m.comment = esc_tag; |
---|
462 | } |
---|
463 | } |
---|
464 | |
---|
465 | album_art = find_album_art(path, song.image, song.image_size); |
---|
466 | |
---|
467 | ret = sql_exec(db, "INSERT into DETAILS" |
---|
468 | " (PATH, SIZE, TIMESTAMP, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE," |
---|
469 | " TITLE, CREATOR, ARTIST, ALBUM, GENRE, COMMENT, DISC, TRACK, DLNA_PN, MIME, ALBUM_ART) " |
---|
470 | "VALUES" |
---|
471 | " (%Q, %lld, %ld, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d, %d, %Q, '%s', %lld);", |
---|
472 | path, file.st_size, file.st_mtime, m.duration, song.channels, song.bitrate, song.samplerate, m.date, |
---|
473 | m.title, m.creator, m.artist, m.album, m.genre, m.comment, song.disc, song.track, |
---|
474 | m.dlna_pn, song.mime?song.mime:m.mime, album_art); |
---|
475 | if( ret != SQLITE_OK ) |
---|
476 | { |
---|
477 | fprintf(stderr, "Error inserting details for '%s'!\n", path); |
---|
478 | ret = 0; |
---|
479 | } |
---|
480 | else |
---|
481 | { |
---|
482 | ret = sqlite3_last_insert_rowid(db); |
---|
483 | } |
---|
484 | freetags(&song); |
---|
485 | free_metadata(&m, free_flags); |
---|
486 | |
---|
487 | return ret; |
---|
488 | } |
---|
489 | |
---|
490 | /* For libjpeg error handling */ |
---|
491 | jmp_buf setjmp_buffer; |
---|
492 | static void |
---|
493 | libjpeg_error_handler(j_common_ptr cinfo) |
---|
494 | { |
---|
495 | cinfo->err->output_message (cinfo); |
---|
496 | longjmp(setjmp_buffer, 1); |
---|
497 | return; |
---|
498 | } |
---|
499 | |
---|
500 | sqlite_int64 |
---|
501 | GetImageMetadata(const char * path, char * name) |
---|
502 | { |
---|
503 | ExifData *ed; |
---|
504 | ExifEntry *e = NULL; |
---|
505 | ExifLoader *l; |
---|
506 | struct jpeg_decompress_struct cinfo; |
---|
507 | struct jpeg_error_mgr jerr; |
---|
508 | FILE *infile; |
---|
509 | int width=0, height=0, thumb=0; |
---|
510 | char make[32], model[64] = {'\0'}; |
---|
511 | char b[1024]; |
---|
512 | struct stat file; |
---|
513 | sqlite_int64 ret; |
---|
514 | image_s * imsrc; |
---|
515 | metadata_t m; |
---|
516 | uint32_t free_flags = 0xFFFFFFFF; |
---|
517 | memset(&m, '\0', sizeof(metadata_t)); |
---|
518 | |
---|
519 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path); |
---|
520 | if ( stat(path, &file) != 0 ) |
---|
521 | return 0; |
---|
522 | strip_ext(name); |
---|
523 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size); |
---|
524 | |
---|
525 | /* MIME hard-coded to JPEG for now, until we add PNG support */ |
---|
526 | asprintf(&m.mime, "image/jpeg"); |
---|
527 | |
---|
528 | l = exif_loader_new(); |
---|
529 | exif_loader_write_file(l, path); |
---|
530 | ed = exif_loader_get_data(l); |
---|
531 | exif_loader_unref(l); |
---|
532 | if( !ed ) |
---|
533 | goto no_exifdata; |
---|
534 | |
---|
535 | e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL); |
---|
536 | if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) ) { |
---|
537 | m.date = strdup(exif_entry_get_value(e, b, sizeof(b))); |
---|
538 | if( strlen(m.date) > 10 ) |
---|
539 | { |
---|
540 | m.date[4] = '-'; |
---|
541 | m.date[7] = '-'; |
---|
542 | m.date[10] = 'T'; |
---|
543 | } |
---|
544 | else { |
---|
545 | free(m.date); |
---|
546 | m.date = NULL; |
---|
547 | } |
---|
548 | } |
---|
549 | else { |
---|
550 | /* One last effort to get the date from XMP */ |
---|
551 | image_get_jpeg_date_xmp(path, &m.date); |
---|
552 | } |
---|
553 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * date: %s\n", m.date); |
---|
554 | |
---|
555 | e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); |
---|
556 | if( e ) |
---|
557 | { |
---|
558 | strncpy(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make)); |
---|
559 | e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL); |
---|
560 | if( e ) |
---|
561 | { |
---|
562 | strncpy(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model)); |
---|
563 | if( !strcasestr(model, make) ) |
---|
564 | snprintf(model, sizeof(model), "%s %s", make, exif_entry_get_value(e, b, sizeof(b))); |
---|
565 | m.creator = strdup(model); |
---|
566 | } |
---|
567 | } |
---|
568 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * model: %s\n", model); |
---|
569 | |
---|
570 | if( ed->size ) |
---|
571 | { |
---|
572 | /* We might need to verify that the thumbnail is 160x160 or smaller */ |
---|
573 | if( ed->size > 12000 ) |
---|
574 | { |
---|
575 | imsrc = image_new_from_jpeg(NULL, 0, (char *)ed->data, ed->size, 1); |
---|
576 | if( imsrc ) |
---|
577 | { |
---|
578 | if( (imsrc->width <= 160) && (imsrc->height <= 160) ) |
---|
579 | thumb = 1; |
---|
580 | image_free(imsrc); |
---|
581 | } |
---|
582 | } |
---|
583 | else |
---|
584 | thumb = 1; |
---|
585 | } |
---|
586 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * thumbnail: %d\n", thumb); |
---|
587 | |
---|
588 | exif_data_unref(ed); |
---|
589 | |
---|
590 | no_exifdata: |
---|
591 | /* If SOF parsing fails, then fall through to reading the JPEG data with libjpeg to get the resolution */ |
---|
592 | if( image_get_jpeg_resolution(path, &width, &height) != 0 || !width || !height ) |
---|
593 | { |
---|
594 | infile = fopen(path, "r"); |
---|
595 | if( infile ) |
---|
596 | { |
---|
597 | cinfo.err = jpeg_std_error(&jerr); |
---|
598 | jerr.error_exit = libjpeg_error_handler; |
---|
599 | jpeg_create_decompress(&cinfo); |
---|
600 | if( setjmp(setjmp_buffer) ) |
---|
601 | goto error; |
---|
602 | jpeg_stdio_src(&cinfo, infile); |
---|
603 | jpeg_read_header(&cinfo, TRUE); |
---|
604 | jpeg_start_decompress(&cinfo); |
---|
605 | width = cinfo.output_width; |
---|
606 | height = cinfo.output_height; |
---|
607 | error: |
---|
608 | jpeg_destroy_decompress(&cinfo); |
---|
609 | fclose(infile); |
---|
610 | } |
---|
611 | } |
---|
612 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * resolution: %dx%d\n", width, height); |
---|
613 | |
---|
614 | if( !width || !height ) |
---|
615 | { |
---|
616 | free_metadata(&m, free_flags); |
---|
617 | return 0; |
---|
618 | } |
---|
619 | if( width <= 640 && height <= 480 ) |
---|
620 | asprintf(&m.dlna_pn, "JPEG_SM;%s", dlna_no_conv); |
---|
621 | else if( width <= 1024 && height <= 768 ) |
---|
622 | asprintf(&m.dlna_pn, "JPEG_MED;%s", dlna_no_conv); |
---|
623 | else if( (width <= 4096 && height <= 4096) || !(GETFLAG(DLNA_STRICT_MASK)) ) |
---|
624 | asprintf(&m.dlna_pn, "JPEG_LRG;%s", dlna_no_conv); |
---|
625 | asprintf(&m.resolution, "%dx%d", width, height); |
---|
626 | |
---|
627 | ret = sql_exec(db, "INSERT into DETAILS" |
---|
628 | " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " |
---|
629 | "VALUES" |
---|
630 | " (%Q, '%q', %lld, %ld, %Q, %Q, %d, %Q, %Q, %Q);", |
---|
631 | path, name, file.st_size, file.st_mtime, m.date, m.resolution, thumb, m.creator, m.dlna_pn, m.mime); |
---|
632 | if( ret != SQLITE_OK ) |
---|
633 | { |
---|
634 | fprintf(stderr, "Error inserting details for '%s'!\n", path); |
---|
635 | ret = 0; |
---|
636 | } |
---|
637 | else |
---|
638 | { |
---|
639 | ret = sqlite3_last_insert_rowid(db); |
---|
640 | } |
---|
641 | free_metadata(&m, free_flags); |
---|
642 | |
---|
643 | return ret; |
---|
644 | } |
---|
645 | |
---|
646 | sqlite_int64 |
---|
647 | GetVideoMetadata(const char * path, char * name) |
---|
648 | { |
---|
649 | struct stat file; |
---|
650 | int ret, i; |
---|
651 | struct tm *modtime; |
---|
652 | AVFormatContext *ctx = NULL; |
---|
653 | AVCodecContext *ac = NULL, *vc = NULL; |
---|
654 | int audio_stream = -1, video_stream = -1; |
---|
655 | enum audio_profiles audio_profile = PROFILE_AUDIO_UNKNOWN; |
---|
656 | char fourcc[4]; |
---|
657 | sqlite_int64 album_art = 0; |
---|
658 | char nfo[PATH_MAX], *ext; |
---|
659 | struct song_metadata video; |
---|
660 | metadata_t m; |
---|
661 | uint32_t free_flags = 0xFFFFFFFF; |
---|
662 | |
---|
663 | memset(&m, '\0', sizeof(m)); |
---|
664 | memset(&video, '\0', sizeof(video)); |
---|
665 | |
---|
666 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing video %s...\n", name); |
---|
667 | if ( stat(path, &file) != 0 ) |
---|
668 | return 0; |
---|
669 | strip_ext(name); |
---|
670 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size); |
---|
671 | |
---|
672 | av_register_all(); |
---|
673 | #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(2<<8)+0) |
---|
674 | if( avformat_open_input(&ctx, path, NULL, NULL) != 0 ) |
---|
675 | #else |
---|
676 | if( av_open_input_file(&ctx, path, NULL, 0, NULL) != 0 ) |
---|
677 | #endif |
---|
678 | { |
---|
679 | DPRINTF(E_WARN, L_METADATA, "Opening %s failed!\n", path); |
---|
680 | return 0; |
---|
681 | } |
---|
682 | av_find_stream_info(ctx); |
---|
683 | //dump_format(ctx, 0, NULL, 0); |
---|
684 | for( i=0; i<ctx->nb_streams; i++) |
---|
685 | { |
---|
686 | if( audio_stream == -1 && |
---|
687 | ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) |
---|
688 | { |
---|
689 | audio_stream = i; |
---|
690 | ac = ctx->streams[audio_stream]->codec; |
---|
691 | continue; |
---|
692 | } |
---|
693 | else if( video_stream == -1 && |
---|
694 | ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) |
---|
695 | { |
---|
696 | video_stream = i; |
---|
697 | vc = ctx->streams[video_stream]->codec; |
---|
698 | continue; |
---|
699 | } |
---|
700 | } |
---|
701 | /* This must not be a video file. */ |
---|
702 | if( !vc ) |
---|
703 | { |
---|
704 | av_close_input_file(ctx); |
---|
705 | if( !is_audio(path) ) |
---|
706 | DPRINTF(E_DEBUG, L_METADATA, "File %s does not contain a video stream.\n", basename(path)); |
---|
707 | return 0; |
---|
708 | } |
---|
709 | |
---|
710 | strcpy(nfo, path); |
---|
711 | ext = strrchr(nfo, '.'); |
---|
712 | if( ext ) |
---|
713 | { |
---|
714 | strcpy(ext+1, "nfo"); |
---|
715 | if( access(nfo, F_OK) == 0 ) |
---|
716 | { |
---|
717 | parse_nfo(nfo, &m); |
---|
718 | } |
---|
719 | } |
---|
720 | |
---|
721 | if( !m.date ) |
---|
722 | { |
---|
723 | m.date = malloc(20); |
---|
724 | modtime = localtime(&file.st_mtime); |
---|
725 | strftime(m.date, 20, "%FT%T", modtime); |
---|
726 | } |
---|
727 | |
---|
728 | if( ac ) |
---|
729 | { |
---|
730 | aac_object_type_t aac_type = AAC_INVALID; |
---|
731 | switch( ac->codec_id ) |
---|
732 | { |
---|
733 | case CODEC_ID_MP3: |
---|
734 | audio_profile = PROFILE_AUDIO_MP3; |
---|
735 | break; |
---|
736 | case CODEC_ID_AAC: |
---|
737 | if( !ac->extradata_size || |
---|
738 | !ac->extradata ) |
---|
739 | { |
---|
740 | DPRINTF(E_DEBUG, L_METADATA, "No AAC type\n"); |
---|
741 | } |
---|
742 | else |
---|
743 | { |
---|
744 | uint8_t data; |
---|
745 | memcpy(&data, ac->extradata, 1); |
---|
746 | aac_type = data >> 3; |
---|
747 | } |
---|
748 | switch( aac_type ) |
---|
749 | { |
---|
750 | /* AAC Low Complexity variants */ |
---|
751 | case AAC_LC: |
---|
752 | case AAC_LC_ER: |
---|
753 | if( ac->sample_rate < 8000 || |
---|
754 | ac->sample_rate > 48000 ) |
---|
755 | { |
---|
756 | DPRINTF(E_DEBUG, L_METADATA, "Unsupported AAC: sample rate is not 8000 < %d < 48000\n", |
---|
757 | ac->sample_rate); |
---|
758 | break; |
---|
759 | } |
---|
760 | /* AAC @ Level 1/2 */ |
---|
761 | if( ac->channels <= 2 && |
---|
762 | ac->bit_rate <= 576000 ) |
---|
763 | audio_profile = PROFILE_AUDIO_AAC; |
---|
764 | else if( ac->channels <= 6 && |
---|
765 | ac->bit_rate <= 1440000 ) |
---|
766 | audio_profile = PROFILE_AUDIO_AAC_MULT5; |
---|
767 | else |
---|
768 | DPRINTF(E_DEBUG, L_METADATA, "Unhandled AAC: %d channels, %d bitrate\n", |
---|
769 | ac->channels, |
---|
770 | ac->bit_rate); |
---|
771 | break; |
---|
772 | default: |
---|
773 | DPRINTF(E_DEBUG, L_METADATA, "Unhandled AAC type [%d]\n", aac_type); |
---|
774 | break; |
---|
775 | } |
---|
776 | break; |
---|
777 | case CODEC_ID_AC3: |
---|
778 | case CODEC_ID_DTS: |
---|
779 | audio_profile = PROFILE_AUDIO_AC3; |
---|
780 | break; |
---|
781 | case CODEC_ID_WMAV1: |
---|
782 | case CODEC_ID_WMAV2: |
---|
783 | /* WMA Baseline: stereo, up to 48 KHz, up to 192,999 bps */ |
---|
784 | if ( ac->bit_rate <= 193000 ) |
---|
785 | audio_profile = PROFILE_AUDIO_WMA_BASE; |
---|
786 | /* WMA Full: stereo, up to 48 KHz, up to 385 Kbps */ |
---|
787 | else if ( ac->bit_rate <= 385000 ) |
---|
788 | audio_profile = PROFILE_AUDIO_WMA_FULL; |
---|
789 | break; |
---|
790 | #if LIBAVCODEC_VERSION_INT > ((51<<16)+(50<<8)+1) |
---|
791 | case CODEC_ID_WMAPRO: |
---|
792 | audio_profile = PROFILE_AUDIO_WMA_PRO; |
---|
793 | break; |
---|
794 | #endif |
---|
795 | case CODEC_ID_MP2: |
---|
796 | audio_profile = PROFILE_AUDIO_MP2; |
---|
797 | break; |
---|
798 | case CODEC_ID_AMR_NB: |
---|
799 | audio_profile = PROFILE_AUDIO_AMR; |
---|
800 | break; |
---|
801 | default: |
---|
802 | if( (ac->codec_id >= CODEC_ID_PCM_S16LE) && |
---|
803 | (ac->codec_id < CODEC_ID_ADPCM_IMA_QT) ) |
---|
804 | audio_profile = PROFILE_AUDIO_PCM; |
---|
805 | else |
---|
806 | DPRINTF(E_DEBUG, L_METADATA, "Unhandled audio codec [0x%X]\n", ac->codec_id); |
---|
807 | break; |
---|
808 | } |
---|
809 | asprintf(&m.frequency, "%u", ac->sample_rate); |
---|
810 | #if LIBAVCODEC_VERSION_INT < (52<<16) |
---|
811 | asprintf(&m.bps, "%u", ac->bits_per_sample); |
---|
812 | #else |
---|
813 | asprintf(&m.bps, "%u", ac->bits_per_coded_sample); |
---|
814 | #endif |
---|
815 | asprintf(&m.channels, "%u", ac->channels); |
---|
816 | } |
---|
817 | if( vc ) |
---|
818 | { |
---|
819 | int off; |
---|
820 | int duration, hours, min, sec, ms; |
---|
821 | ts_timestamp_t ts_timestamp = NONE; |
---|
822 | DPRINTF(E_DEBUG, L_METADATA, "Container: '%s' [%s]\n", ctx->iformat->name, basename(path)); |
---|
823 | asprintf(&m.resolution, "%dx%d", vc->width, vc->height); |
---|
824 | if( ctx->bit_rate > 8 ) |
---|
825 | asprintf(&m.bitrate, "%u", ctx->bit_rate / 8); |
---|
826 | if( ctx->duration > 0 ) { |
---|
827 | duration = (int)(ctx->duration / AV_TIME_BASE); |
---|
828 | hours = (int)(duration / 3600); |
---|
829 | min = (int)(duration / 60 % 60); |
---|
830 | sec = (int)(duration % 60); |
---|
831 | ms = (int)(ctx->duration / (AV_TIME_BASE/1000) % 1000); |
---|
832 | asprintf(&m.duration, "%d:%02d:%02d.%03d", hours, min, sec, ms); |
---|
833 | } |
---|
834 | |
---|
835 | /* NOTE: The DLNA spec only provides for ASF (WMV), TS, PS, and MP4 containers. |
---|
836 | * Skip DLNA parsing for everything else. */ |
---|
837 | if( strcmp(ctx->iformat->name, "avi") == 0 ) |
---|
838 | { |
---|
839 | asprintf(&m.mime, "video/x-msvideo"); |
---|
840 | if( vc->codec_id == CODEC_ID_MPEG4 ) |
---|
841 | { |
---|
842 | fourcc[0] = vc->codec_tag & 0xff; |
---|
843 | fourcc[1] = vc->codec_tag>>8 & 0xff; |
---|
844 | fourcc[2] = vc->codec_tag>>16 & 0xff; |
---|
845 | fourcc[3] = vc->codec_tag>>24 & 0xff; |
---|
846 | if( memcmp(fourcc, "XVID", 4) == 0 || |
---|
847 | memcmp(fourcc, "DX50", 4) == 0 || |
---|
848 | memcmp(fourcc, "DIVX", 4) == 0 ) |
---|
849 | asprintf(&m.creator, "DiVX"); |
---|
850 | } |
---|
851 | } |
---|
852 | else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 && |
---|
853 | ends_with(path, ".mov") ) |
---|
854 | asprintf(&m.mime, "video/quicktime"); |
---|
855 | else if( strncmp(ctx->iformat->name, "matroska", 8) == 0 ) |
---|
856 | asprintf(&m.mime, "video/x-matroska"); |
---|
857 | else if( strcmp(ctx->iformat->name, "flv") == 0 ) |
---|
858 | asprintf(&m.mime, "video/x-flv"); |
---|
859 | if( m.mime ) |
---|
860 | goto video_no_dlna; |
---|
861 | |
---|
862 | switch( vc->codec_id ) |
---|
863 | { |
---|
864 | case CODEC_ID_MPEG1VIDEO: |
---|
865 | if( strcmp(ctx->iformat->name, "mpeg") == 0 ) |
---|
866 | { |
---|
867 | if( (vc->width == 352) && |
---|
868 | (vc->height <= 288) ) |
---|
869 | { |
---|
870 | asprintf(&m.dlna_pn, "MPEG1;%s", dlna_no_conv); |
---|
871 | } |
---|
872 | asprintf(&m.mime, "video/mpeg"); |
---|
873 | } |
---|
874 | break; |
---|
875 | case CODEC_ID_MPEG2VIDEO: |
---|
876 | m.dlna_pn = malloc(64); |
---|
877 | off = sprintf(m.dlna_pn, "MPEG_"); |
---|
878 | if( strcmp(ctx->iformat->name, "mpegts") == 0 ) |
---|
879 | { |
---|
880 | int raw_packet_size; |
---|
881 | int dlna_ts_present = dlna_timestamp_is_present(path, &raw_packet_size); |
---|
882 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is %s MPEG2 TS packet size %d\n", |
---|
883 | video_stream, basename(path), m.resolution, raw_packet_size); |
---|
884 | off += sprintf(m.dlna_pn+off, "TS_"); |
---|
885 | if( (vc->width >= 1280) && |
---|
886 | (vc->height >= 720) ) |
---|
887 | { |
---|
888 | off += sprintf(m.dlna_pn+off, "HD_NA"); |
---|
889 | } |
---|
890 | else |
---|
891 | { |
---|
892 | off += sprintf(m.dlna_pn+off, "SD_"); |
---|
893 | if( (vc->height == 576) || |
---|
894 | (vc->height == 288) ) |
---|
895 | off += sprintf(m.dlna_pn+off, "EU"); |
---|
896 | else |
---|
897 | off += sprintf(m.dlna_pn+off, "NA"); |
---|
898 | } |
---|
899 | if( raw_packet_size == MPEG_TS_PACKET_LENGTH_DLNA ) |
---|
900 | { |
---|
901 | if (dlna_ts_present) |
---|
902 | ts_timestamp = VALID; |
---|
903 | else |
---|
904 | ts_timestamp = EMPTY; |
---|
905 | } |
---|
906 | else if( raw_packet_size != MPEG_TS_PACKET_LENGTH ) |
---|
907 | { |
---|
908 | DPRINTF(E_DEBUG, L_METADATA, "Unsupported DLNA TS packet size [%d] (%s)\n", |
---|
909 | raw_packet_size, basename(path)); |
---|
910 | free(m.dlna_pn); |
---|
911 | m.dlna_pn = NULL; |
---|
912 | } |
---|
913 | switch( ts_timestamp ) |
---|
914 | { |
---|
915 | case NONE: |
---|
916 | asprintf(&m.mime, "video/mpeg"); |
---|
917 | if( m.dlna_pn ) |
---|
918 | off += sprintf(m.dlna_pn+off, "_ISO"); |
---|
919 | break; |
---|
920 | case VALID: |
---|
921 | off += sprintf(m.dlna_pn+off, "_T"); |
---|
922 | case EMPTY: |
---|
923 | asprintf(&m.mime, "video/vnd.dlna.mpeg-tts"); |
---|
924 | default: |
---|
925 | break; |
---|
926 | } |
---|
927 | } |
---|
928 | else if( strcmp(ctx->iformat->name, "mpeg") == 0 ) |
---|
929 | { |
---|
930 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is %s MPEG2 PS\n", |
---|
931 | video_stream, basename(path), m.resolution); |
---|
932 | off += sprintf(m.dlna_pn+off, "PS_"); |
---|
933 | if( (vc->height == 576) || |
---|
934 | (vc->height == 288) ) |
---|
935 | off += sprintf(m.dlna_pn+off, "PAL"); |
---|
936 | else |
---|
937 | off += sprintf(m.dlna_pn+off, "NTSC"); |
---|
938 | asprintf(&m.mime, "video/mpeg"); |
---|
939 | } |
---|
940 | else |
---|
941 | { |
---|
942 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s [%s] is %s non-DLNA MPEG2\n", |
---|
943 | video_stream, basename(path), ctx->iformat->name, m.resolution); |
---|
944 | free(m.dlna_pn); |
---|
945 | m.dlna_pn = NULL; |
---|
946 | } |
---|
947 | if( m.dlna_pn ) |
---|
948 | sprintf(m.dlna_pn+off, ";%s", dlna_no_conv); |
---|
949 | break; |
---|
950 | case CODEC_ID_H264: |
---|
951 | m.dlna_pn = malloc(128); |
---|
952 | off = sprintf(m.dlna_pn, "AVC_"); |
---|
953 | |
---|
954 | if( strcmp(ctx->iformat->name, "mpegts") == 0 ) |
---|
955 | { |
---|
956 | AVRational display_aspect_ratio; |
---|
957 | int fps, interlaced; |
---|
958 | int raw_packet_size; |
---|
959 | int dlna_ts_present = dlna_timestamp_is_present(path, &raw_packet_size); |
---|
960 | |
---|
961 | off += sprintf(m.dlna_pn+off, "TS_"); |
---|
962 | if (vc->sample_aspect_ratio.num) { |
---|
963 | av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, |
---|
964 | vc->width * vc->sample_aspect_ratio.num, |
---|
965 | vc->height * vc->sample_aspect_ratio.den, |
---|
966 | 1024*1024); |
---|
967 | } |
---|
968 | fps = ctx->streams[video_stream]->r_frame_rate.num / ctx->streams[video_stream]->r_frame_rate.den; |
---|
969 | interlaced = (ctx->streams[video_stream]->r_frame_rate.num / vc->time_base.den); |
---|
970 | if( ((((vc->width == 1920 || vc->width == 1440) && vc->height == 1080) || |
---|
971 | (vc->width == 720 && vc->height == 480)) && fps == 59 && interlaced) || |
---|
972 | ((vc->width == 1280 && vc->height == 720) && fps == 59 && !interlaced) ) |
---|
973 | { |
---|
974 | if( (vc->profile == FF_PROFILE_H264_MAIN || vc->profile == FF_PROFILE_H264_HIGH) && |
---|
975 | audio_profile == PROFILE_AUDIO_AC3 ) |
---|
976 | { |
---|
977 | off += sprintf(m.dlna_pn+off, "HD_60_"); |
---|
978 | vc->profile = FF_PROFILE_SKIP; |
---|
979 | } |
---|
980 | } |
---|
981 | else if( ((vc->width == 1920 && vc->height == 1080) || |
---|
982 | (vc->width == 1440 && vc->height == 1080) || |
---|
983 | (vc->width == 1280 && vc->height == 720) || |
---|
984 | (vc->width == 720 && vc->height == 576)) && |
---|
985 | interlaced && fps == 50 ) |
---|
986 | { |
---|
987 | if( (vc->profile == FF_PROFILE_H264_MAIN || vc->profile == FF_PROFILE_H264_HIGH) && |
---|
988 | audio_profile == PROFILE_AUDIO_AC3 ) |
---|
989 | { |
---|
990 | off += sprintf(m.dlna_pn+off, "HD_50_"); |
---|
991 | vc->profile = FF_PROFILE_SKIP; |
---|
992 | } |
---|
993 | } |
---|
994 | switch( vc->profile ) |
---|
995 | { |
---|
996 | case FF_PROFILE_H264_BASELINE: |
---|
997 | off += sprintf(m.dlna_pn+off, "BL_"); |
---|
998 | if( vc->width <= 352 && |
---|
999 | vc->height <= 288 && |
---|
1000 | vc->bit_rate <= 384000 ) |
---|
1001 | { |
---|
1002 | off += sprintf(m.dlna_pn+off, "CIF15_"); |
---|
1003 | break; |
---|
1004 | } |
---|
1005 | else if( vc->width <= 352 && |
---|
1006 | vc->height <= 288 && |
---|
1007 | vc->bit_rate <= 3000000 ) |
---|
1008 | { |
---|
1009 | off += sprintf(m.dlna_pn+off, "CIF30_"); |
---|
1010 | break; |
---|
1011 | } |
---|
1012 | /* Fall back to Main Profile if it doesn't match a Baseline DLNA profile. */ |
---|
1013 | else |
---|
1014 | off -= 3; |
---|
1015 | default: |
---|
1016 | case FF_PROFILE_H264_MAIN: |
---|
1017 | off += sprintf(m.dlna_pn+off, "MP_"); |
---|
1018 | if( vc->profile != FF_PROFILE_H264_BASELINE && |
---|
1019 | vc->profile != FF_PROFILE_H264_MAIN ) |
---|
1020 | { |
---|
1021 | DPRINTF(E_DEBUG, L_METADATA, "Unknown AVC profile %d; assuming MP. [%s]\n", |
---|
1022 | vc->profile, basename(path)); |
---|
1023 | } |
---|
1024 | if( vc->width <= 720 && |
---|
1025 | vc->height <= 576 && |
---|
1026 | vc->bit_rate <= 10000000 ) |
---|
1027 | { |
---|
1028 | off += sprintf(m.dlna_pn+off, "SD_"); |
---|
1029 | } |
---|
1030 | else if( vc->width <= 1920 && |
---|
1031 | vc->height <= 1152 && |
---|
1032 | vc->bit_rate <= 20000000 ) |
---|
1033 | { |
---|
1034 | off += sprintf(m.dlna_pn+off, "HD_"); |
---|
1035 | } |
---|
1036 | else |
---|
1037 | { |
---|
1038 | DPRINTF(E_DEBUG, L_METADATA, "Unsupported h.264 video profile! [%s, %dx%d, %dbps : %s]\n", |
---|
1039 | m.dlna_pn, vc->width, vc->height, vc->bit_rate, basename(path)); |
---|
1040 | free(m.dlna_pn); |
---|
1041 | m.dlna_pn = NULL; |
---|
1042 | } |
---|
1043 | break; |
---|
1044 | case FF_PROFILE_H264_HIGH: |
---|
1045 | off += sprintf(m.dlna_pn+off, "HP_"); |
---|
1046 | if( vc->width <= 1920 && |
---|
1047 | vc->height <= 1152 && |
---|
1048 | vc->bit_rate <= 30000000 && |
---|
1049 | audio_profile == PROFILE_AUDIO_AC3 ) |
---|
1050 | { |
---|
1051 | off += sprintf(m.dlna_pn+off, "HD_"); |
---|
1052 | } |
---|
1053 | else |
---|
1054 | { |
---|
1055 | DPRINTF(E_DEBUG, L_METADATA, "Unsupported h.264 HP video profile! [%dbps, %d audio : %s]\n", |
---|
1056 | vc->bit_rate, audio_profile, basename(path)); |
---|
1057 | free(m.dlna_pn); |
---|
1058 | m.dlna_pn = NULL; |
---|
1059 | } |
---|
1060 | break; |
---|
1061 | case FF_PROFILE_SKIP: |
---|
1062 | break; |
---|
1063 | } |
---|
1064 | if( !m.dlna_pn ) |
---|
1065 | break; |
---|
1066 | switch( audio_profile ) |
---|
1067 | { |
---|
1068 | case PROFILE_AUDIO_MP3: |
---|
1069 | off += sprintf(m.dlna_pn+off, "MPEG1_L3"); |
---|
1070 | break; |
---|
1071 | case PROFILE_AUDIO_AC3: |
---|
1072 | off += sprintf(m.dlna_pn+off, "AC3"); |
---|
1073 | break; |
---|
1074 | case PROFILE_AUDIO_AAC: |
---|
1075 | case PROFILE_AUDIO_AAC_MULT5: |
---|
1076 | off += sprintf(m.dlna_pn+off, "AAC_MULT5"); |
---|
1077 | break; |
---|
1078 | default: |
---|
1079 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for %s file [%s]\n", |
---|
1080 | m.dlna_pn, basename(path)); |
---|
1081 | free(m.dlna_pn); |
---|
1082 | m.dlna_pn = NULL; |
---|
1083 | break; |
---|
1084 | } |
---|
1085 | if( !m.dlna_pn ) |
---|
1086 | break; |
---|
1087 | if( raw_packet_size == MPEG_TS_PACKET_LENGTH_DLNA ) |
---|
1088 | { |
---|
1089 | if( vc->profile == FF_PROFILE_H264_HIGH || |
---|
1090 | dlna_ts_present ) |
---|
1091 | ts_timestamp = VALID; |
---|
1092 | else |
---|
1093 | ts_timestamp = EMPTY; |
---|
1094 | } |
---|
1095 | else if( raw_packet_size != MPEG_TS_PACKET_LENGTH ) |
---|
1096 | { |
---|
1097 | DPRINTF(E_DEBUG, L_METADATA, "Unsupported DLNA TS packet size [%d] (%s)\n", |
---|
1098 | raw_packet_size, basename(path)); |
---|
1099 | free(m.dlna_pn); |
---|
1100 | m.dlna_pn = NULL; |
---|
1101 | } |
---|
1102 | switch( ts_timestamp ) |
---|
1103 | { |
---|
1104 | case NONE: |
---|
1105 | if( m.dlna_pn ) |
---|
1106 | off += sprintf(m.dlna_pn+off, "_ISO"); |
---|
1107 | break; |
---|
1108 | case VALID: |
---|
1109 | off += sprintf(m.dlna_pn+off, "_T"); |
---|
1110 | case EMPTY: |
---|
1111 | asprintf(&m.mime, "video/vnd.dlna.mpeg-tts"); |
---|
1112 | default: |
---|
1113 | break; |
---|
1114 | } |
---|
1115 | } |
---|
1116 | else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) |
---|
1117 | { |
---|
1118 | off += sprintf(m.dlna_pn+off, "MP4_"); |
---|
1119 | |
---|
1120 | switch( vc->profile ) { |
---|
1121 | case FF_PROFILE_H264_BASELINE: |
---|
1122 | if( vc->width <= 352 && |
---|
1123 | vc->height <= 288 ) |
---|
1124 | { |
---|
1125 | if( ctx->bit_rate < 600000 ) |
---|
1126 | off += sprintf(m.dlna_pn+off, "BL_CIF15_"); |
---|
1127 | else if( ctx->bit_rate < 5000000 ) |
---|
1128 | off += sprintf(m.dlna_pn+off, "BL_CIF30_"); |
---|
1129 | else |
---|
1130 | goto mp4_mp_fallback; |
---|
1131 | |
---|
1132 | if( audio_profile == PROFILE_AUDIO_AMR ) |
---|
1133 | { |
---|
1134 | off += sprintf(m.dlna_pn+off, "AMR"); |
---|
1135 | } |
---|
1136 | else if( audio_profile == PROFILE_AUDIO_AAC ) |
---|
1137 | { |
---|
1138 | off += sprintf(m.dlna_pn+off, "AAC_"); |
---|
1139 | if( ctx->bit_rate < 520000 ) |
---|
1140 | { |
---|
1141 | off += sprintf(m.dlna_pn+off, "520"); |
---|
1142 | } |
---|
1143 | else if( ctx->bit_rate < 940000 ) |
---|
1144 | { |
---|
1145 | off += sprintf(m.dlna_pn+off, "940"); |
---|
1146 | } |
---|
1147 | else |
---|
1148 | { |
---|
1149 | off -= 13; |
---|
1150 | goto mp4_mp_fallback; |
---|
1151 | } |
---|
1152 | } |
---|
1153 | else |
---|
1154 | { |
---|
1155 | off -= 9; |
---|
1156 | goto mp4_mp_fallback; |
---|
1157 | } |
---|
1158 | } |
---|
1159 | else if( vc->width <= 720 && |
---|
1160 | vc->height <= 576 ) |
---|
1161 | { |
---|
1162 | if( vc->level == 30 && |
---|
1163 | audio_profile == PROFILE_AUDIO_AAC && |
---|
1164 | ctx->bit_rate <= 5000000 ) |
---|
1165 | off += sprintf(m.dlna_pn+off, "BL_L3L_SD_AAC"); |
---|
1166 | else if( vc->level <= 31 && |
---|
1167 | audio_profile == PROFILE_AUDIO_AAC && |
---|
1168 | ctx->bit_rate <= 15000000 ) |
---|
1169 | off += sprintf(m.dlna_pn+off, "BL_L31_HD_AAC"); |
---|
1170 | else |
---|
1171 | goto mp4_mp_fallback; |
---|
1172 | } |
---|
1173 | else if( vc->width <= 1280 && |
---|
1174 | vc->height <= 720 ) |
---|
1175 | { |
---|
1176 | if( vc->level <= 31 && |
---|
1177 | audio_profile == PROFILE_AUDIO_AAC && |
---|
1178 | ctx->bit_rate <= 15000000 ) |
---|
1179 | off += sprintf(m.dlna_pn+off, "BL_L31_HD_AAC"); |
---|
1180 | else if( vc->level <= 32 && |
---|
1181 | audio_profile == PROFILE_AUDIO_AAC && |
---|
1182 | ctx->bit_rate <= 21000000 ) |
---|
1183 | off += sprintf(m.dlna_pn+off, "BL_L32_HD_AAC"); |
---|
1184 | else |
---|
1185 | goto mp4_mp_fallback; |
---|
1186 | } |
---|
1187 | else |
---|
1188 | goto mp4_mp_fallback; |
---|
1189 | break; |
---|
1190 | case FF_PROFILE_H264_MAIN: |
---|
1191 | mp4_mp_fallback: |
---|
1192 | off += sprintf(m.dlna_pn+off, "MP_"); |
---|
1193 | /* AVC MP4 SD profiles - 10 Mbps max */ |
---|
1194 | if( vc->width <= 720 && |
---|
1195 | vc->height <= 576 && |
---|
1196 | vc->bit_rate <= 10000000 ) |
---|
1197 | { |
---|
1198 | sprintf(m.dlna_pn+off, "SD_"); |
---|
1199 | if( audio_profile == PROFILE_AUDIO_AC3 ) |
---|
1200 | off += sprintf(m.dlna_pn+off, "AC3"); |
---|
1201 | else if( audio_profile == PROFILE_AUDIO_AAC || |
---|
1202 | audio_profile == PROFILE_AUDIO_AAC_MULT5 ) |
---|
1203 | off += sprintf(m.dlna_pn+off, "AAC_MULT5"); |
---|
1204 | else if( audio_profile == PROFILE_AUDIO_MP3 ) |
---|
1205 | off += sprintf(m.dlna_pn+off, "MPEG1_L3"); |
---|
1206 | else |
---|
1207 | m.dlna_pn[10] = '\0'; |
---|
1208 | } |
---|
1209 | else if( vc->width <= 1280 && |
---|
1210 | vc->height <= 720 && |
---|
1211 | vc->bit_rate <= 15000000 && |
---|
1212 | audio_profile == PROFILE_AUDIO_AAC ) |
---|
1213 | { |
---|
1214 | off += sprintf(m.dlna_pn+off, "HD_720p_AAC"); |
---|
1215 | } |
---|
1216 | else if( vc->width <= 1920 && |
---|
1217 | vc->height <= 1080 && |
---|
1218 | vc->bit_rate <= 21000000 && |
---|
1219 | audio_profile == PROFILE_AUDIO_AAC ) |
---|
1220 | { |
---|
1221 | off += sprintf(m.dlna_pn+off, "HD_1080i_AAC"); |
---|
1222 | } |
---|
1223 | if( strlen(m.dlna_pn) <= 11 ) |
---|
1224 | { |
---|
1225 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for %s file %s\n", |
---|
1226 | m.dlna_pn, basename(path)); |
---|
1227 | free(m.dlna_pn); |
---|
1228 | m.dlna_pn = NULL; |
---|
1229 | } |
---|
1230 | break; |
---|
1231 | case FF_PROFILE_H264_HIGH: |
---|
1232 | if( vc->width <= 1920 && |
---|
1233 | vc->height <= 1080 && |
---|
1234 | vc->bit_rate <= 25000000 && |
---|
1235 | audio_profile == PROFILE_AUDIO_AAC ) |
---|
1236 | { |
---|
1237 | off += sprintf(m.dlna_pn+off, "HP_HD_AAC"); |
---|
1238 | } |
---|
1239 | break; |
---|
1240 | default: |
---|
1241 | DPRINTF(E_DEBUG, L_METADATA, "AVC profile [%d] not recognized for file %s\n", |
---|
1242 | vc->profile, basename(path)); |
---|
1243 | free(m.dlna_pn); |
---|
1244 | m.dlna_pn = NULL; |
---|
1245 | break; |
---|
1246 | } |
---|
1247 | } |
---|
1248 | else |
---|
1249 | { |
---|
1250 | free(m.dlna_pn); |
---|
1251 | m.dlna_pn = NULL; |
---|
1252 | } |
---|
1253 | if( m.dlna_pn ) |
---|
1254 | sprintf(m.dlna_pn+off, ";%s", dlna_no_conv); |
---|
1255 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is h.264\n", video_stream, basename(path)); |
---|
1256 | break; |
---|
1257 | case CODEC_ID_MPEG4: |
---|
1258 | fourcc[0] = vc->codec_tag & 0xff; |
---|
1259 | fourcc[1] = vc->codec_tag>>8 & 0xff; |
---|
1260 | fourcc[2] = vc->codec_tag>>16 & 0xff; |
---|
1261 | fourcc[3] = vc->codec_tag>>24 & 0xff; |
---|
1262 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is MPEG4 [%c%c%c%c/0x%X]\n", |
---|
1263 | video_stream, basename(path), |
---|
1264 | isprint(fourcc[0]) ? fourcc[0] : '_', |
---|
1265 | isprint(fourcc[1]) ? fourcc[1] : '_', |
---|
1266 | isprint(fourcc[2]) ? fourcc[2] : '_', |
---|
1267 | isprint(fourcc[3]) ? fourcc[3] : '_', |
---|
1268 | vc->codec_tag); |
---|
1269 | |
---|
1270 | if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) |
---|
1271 | { |
---|
1272 | m.dlna_pn = malloc(128); |
---|
1273 | off = sprintf(m.dlna_pn, "MPEG4_P2_"); |
---|
1274 | |
---|
1275 | if( ends_with(path, ".3gp") ) |
---|
1276 | { |
---|
1277 | asprintf(&m.mime, "video/3gpp"); |
---|
1278 | switch( audio_profile ) |
---|
1279 | { |
---|
1280 | case PROFILE_AUDIO_AAC: |
---|
1281 | off += sprintf(m.dlna_pn+off, "3GPP_SP_L0B_AAC"); |
---|
1282 | break; |
---|
1283 | case PROFILE_AUDIO_AMR: |
---|
1284 | off += sprintf(m.dlna_pn+off, "3GPP_SP_L0B_AMR"); |
---|
1285 | break; |
---|
1286 | default: |
---|
1287 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for MPEG4-P2 3GP/0x%X file %s\n", |
---|
1288 | ac->codec_id, basename(path)); |
---|
1289 | free(m.dlna_pn); |
---|
1290 | m.dlna_pn = NULL; |
---|
1291 | break; |
---|
1292 | } |
---|
1293 | } |
---|
1294 | else |
---|
1295 | { |
---|
1296 | if( ctx->bit_rate <= 1000000 && |
---|
1297 | audio_profile == PROFILE_AUDIO_AAC ) |
---|
1298 | { |
---|
1299 | off += sprintf(m.dlna_pn+off, "MP4_ASP_AAC"); |
---|
1300 | } |
---|
1301 | else if( ctx->bit_rate <= 4000000 && |
---|
1302 | vc->width <= 640 && |
---|
1303 | vc->height <= 480 && |
---|
1304 | audio_profile == PROFILE_AUDIO_AAC ) |
---|
1305 | { |
---|
1306 | off += sprintf(m.dlna_pn+off, "MP4_SP_VGA_AAC"); |
---|
1307 | } |
---|
1308 | else |
---|
1309 | { |
---|
1310 | DPRINTF(E_DEBUG, L_METADATA, "Unsupported h.264 video profile! [%dx%d, %dbps]\n", |
---|
1311 | vc->width, |
---|
1312 | vc->height, |
---|
1313 | ctx->bit_rate); |
---|
1314 | free(m.dlna_pn); |
---|
1315 | m.dlna_pn = NULL; |
---|
1316 | } |
---|
1317 | } |
---|
1318 | if( m.dlna_pn ) |
---|
1319 | sprintf(m.dlna_pn+off, ";%s", dlna_no_conv); |
---|
1320 | } |
---|
1321 | break; |
---|
1322 | case CODEC_ID_WMV3: |
---|
1323 | /* I'm not 100% sure this is correct, but it works on everything I could get my hands on */ |
---|
1324 | if( vc->extradata_size > 0 ) |
---|
1325 | { |
---|
1326 | if( !((vc->extradata[0] >> 3) & 1) ) |
---|
1327 | vc->level = 0; |
---|
1328 | if( !((vc->extradata[0] >> 6) & 1) ) |
---|
1329 | vc->profile = 0; |
---|
1330 | } |
---|
1331 | case CODEC_ID_VC1: |
---|
1332 | if( strcmp(ctx->iformat->name, "asf") != 0 ) |
---|
1333 | { |
---|
1334 | DPRINTF(E_DEBUG, L_METADATA, "Skipping DLNA parsing for non-ASF VC1 file %s\n", path); |
---|
1335 | break; |
---|
1336 | } |
---|
1337 | m.dlna_pn = malloc(64); |
---|
1338 | off = sprintf(m.dlna_pn, "WMV"); |
---|
1339 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is VC1\n", video_stream, basename(path)); |
---|
1340 | asprintf(&m.mime, "video/x-ms-wmv"); |
---|
1341 | if( (vc->width <= 176) && |
---|
1342 | (vc->height <= 144) && |
---|
1343 | (vc->level == 0) ) |
---|
1344 | { |
---|
1345 | off += sprintf(m.dlna_pn+off, "SPLL_"); |
---|
1346 | switch( audio_profile ) |
---|
1347 | { |
---|
1348 | case PROFILE_AUDIO_MP3: |
---|
1349 | off += sprintf(m.dlna_pn+off, "MP3"); |
---|
1350 | break; |
---|
1351 | case PROFILE_AUDIO_WMA_BASE: |
---|
1352 | off += sprintf(m.dlna_pn+off, "BASE"); |
---|
1353 | break; |
---|
1354 | default: |
---|
1355 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVSPLL/0x%X file %s\n", |
---|
1356 | audio_profile, basename(path)); |
---|
1357 | free(m.dlna_pn); |
---|
1358 | m.dlna_pn = NULL; |
---|
1359 | break; |
---|
1360 | } |
---|
1361 | } |
---|
1362 | else if( (vc->width <= 352) && |
---|
1363 | (vc->height <= 288) && |
---|
1364 | (vc->profile == 0) && |
---|
1365 | (ctx->bit_rate/8 <= 384000) ) |
---|
1366 | { |
---|
1367 | off += sprintf(m.dlna_pn+off, "SPML_"); |
---|
1368 | switch( audio_profile ) |
---|
1369 | { |
---|
1370 | case PROFILE_AUDIO_MP3: |
---|
1371 | off += sprintf(m.dlna_pn+off, "MP3"); |
---|
1372 | break; |
---|
1373 | case PROFILE_AUDIO_WMA_BASE: |
---|
1374 | off += sprintf(m.dlna_pn+off, "BASE"); |
---|
1375 | break; |
---|
1376 | default: |
---|
1377 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVSPML/0x%X file %s\n", |
---|
1378 | audio_profile, basename(path)); |
---|
1379 | free(m.dlna_pn); |
---|
1380 | m.dlna_pn = NULL; |
---|
1381 | break; |
---|
1382 | } |
---|
1383 | } |
---|
1384 | else if( (vc->width <= 720) && |
---|
1385 | (vc->height <= 576) && |
---|
1386 | (ctx->bit_rate/8 <= 10000000) ) |
---|
1387 | { |
---|
1388 | off += sprintf(m.dlna_pn+off, "MED_"); |
---|
1389 | switch( audio_profile ) |
---|
1390 | { |
---|
1391 | case PROFILE_AUDIO_WMA_PRO: |
---|
1392 | off += sprintf(m.dlna_pn+off, "PRO"); |
---|
1393 | break; |
---|
1394 | case PROFILE_AUDIO_WMA_FULL: |
---|
1395 | off += sprintf(m.dlna_pn+off, "FULL"); |
---|
1396 | break; |
---|
1397 | case PROFILE_AUDIO_WMA_BASE: |
---|
1398 | off += sprintf(m.dlna_pn+off, "BASE"); |
---|
1399 | break; |
---|
1400 | default: |
---|
1401 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVMED/0x%X file %s\n", |
---|
1402 | audio_profile, basename(path)); |
---|
1403 | free(m.dlna_pn); |
---|
1404 | m.dlna_pn = NULL; |
---|
1405 | break; |
---|
1406 | } |
---|
1407 | } |
---|
1408 | else if( (vc->width <= 1920) && |
---|
1409 | (vc->height <= 1080) && |
---|
1410 | (ctx->bit_rate/8 <= 20000000) ) |
---|
1411 | { |
---|
1412 | off += sprintf(m.dlna_pn+off, "HIGH_"); |
---|
1413 | switch( audio_profile ) |
---|
1414 | { |
---|
1415 | case PROFILE_AUDIO_WMA_PRO: |
---|
1416 | off += sprintf(m.dlna_pn+off, "PRO"); |
---|
1417 | break; |
---|
1418 | case PROFILE_AUDIO_WMA_FULL: |
---|
1419 | off += sprintf(m.dlna_pn+off, "FULL"); |
---|
1420 | break; |
---|
1421 | default: |
---|
1422 | DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVHIGH/0x%X file %s\n", |
---|
1423 | audio_profile, basename(path)); |
---|
1424 | free(m.dlna_pn); |
---|
1425 | m.dlna_pn = NULL; |
---|
1426 | break; |
---|
1427 | } |
---|
1428 | } |
---|
1429 | if( m.dlna_pn ) |
---|
1430 | sprintf(m.dlna_pn+off, ";%s", dlna_no_conv); |
---|
1431 | break; |
---|
1432 | case CODEC_ID_MSMPEG4V3: |
---|
1433 | asprintf(&m.mime, "video/x-msvideo"); |
---|
1434 | default: |
---|
1435 | DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is %s [type %d]\n", |
---|
1436 | video_stream, basename(path), m.resolution, vc->codec_id); |
---|
1437 | break; |
---|
1438 | } |
---|
1439 | } |
---|
1440 | if( !m.mime ) |
---|
1441 | { |
---|
1442 | if( strcmp(ctx->iformat->name, "avi") == 0 ) |
---|
1443 | asprintf(&m.mime, "video/x-msvideo"); |
---|
1444 | else if( strncmp(ctx->iformat->name, "mpeg", 4) == 0 ) |
---|
1445 | asprintf(&m.mime, "video/mpeg"); |
---|
1446 | else if( strcmp(ctx->iformat->name, "asf") == 0 ) |
---|
1447 | asprintf(&m.mime, "video/x-ms-wmv"); |
---|
1448 | else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) |
---|
1449 | if( ends_with(path, ".mov") ) |
---|
1450 | asprintf(&m.mime, "video/quicktime"); |
---|
1451 | else |
---|
1452 | asprintf(&m.mime, "video/mp4"); |
---|
1453 | else if( strncmp(ctx->iformat->name, "matroska", 8) == 0 ) |
---|
1454 | asprintf(&m.mime, "video/x-matroska"); |
---|
1455 | else if( strcmp(ctx->iformat->name, "flv") == 0 ) |
---|
1456 | asprintf(&m.mime, "video/x-flv"); |
---|
1457 | else |
---|
1458 | DPRINTF(E_WARN, L_METADATA, "%s: Unhandled format: %s\n", path, ctx->iformat->name); |
---|
1459 | } |
---|
1460 | |
---|
1461 | if( strcmp(ctx->iformat->name, "asf") == 0 ) |
---|
1462 | { |
---|
1463 | if( readtags((char *)path, &video, &file, "en_US", "asf") == 0 ) |
---|
1464 | { |
---|
1465 | if( video.title && *video.title ) |
---|
1466 | { |
---|
1467 | m.title = escape_tag(trim(video.title), 1); |
---|
1468 | } |
---|
1469 | if( video.genre && *video.genre ) |
---|
1470 | { |
---|
1471 | m.genre = escape_tag(trim(video.genre), 1); |
---|
1472 | } |
---|
1473 | if( video.contributor[ROLE_TRACKARTIST] && *video.contributor[ROLE_TRACKARTIST] ) |
---|
1474 | { |
---|
1475 | m.artist = escape_tag(trim(video.contributor[ROLE_TRACKARTIST]), 1); |
---|
1476 | } |
---|
1477 | if( video.contributor[ROLE_ALBUMARTIST] && *video.contributor[ROLE_ALBUMARTIST] ) |
---|
1478 | { |
---|
1479 | m.creator = escape_tag(trim(video.contributor[ROLE_ALBUMARTIST]), 1); |
---|
1480 | } |
---|
1481 | else |
---|
1482 | { |
---|
1483 | m.creator = m.artist; |
---|
1484 | free_flags &= ~FLAG_CREATOR; |
---|
1485 | } |
---|
1486 | } |
---|
1487 | } |
---|
1488 | #ifndef NETGEAR |
---|
1489 | #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) |
---|
1490 | else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) |
---|
1491 | { |
---|
1492 | if( ctx->metadata ) |
---|
1493 | { |
---|
1494 | AVMetadataTag *tag = NULL; |
---|
1495 | |
---|
1496 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, "Metadata:\n"); |
---|
1497 | while( (tag = av_metadata_get(ctx->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX)) ) |
---|
1498 | { |
---|
1499 | //DEBUG DPRINTF(E_DEBUG, L_METADATA, " %-16s: %s\n", tag->key, tag->value); |
---|
1500 | if( strcmp(tag->key, "title") == 0 ) |
---|
1501 | m.title = escape_tag(trim(tag->value), 1); |
---|
1502 | else if( strcmp(tag->key, "genre") == 0 ) |
---|
1503 | m.genre = escape_tag(trim(tag->value), 1); |
---|
1504 | else if( strcmp(tag->key, "artist") == 0 ) |
---|
1505 | m.artist = escape_tag(trim(tag->value), 1); |
---|
1506 | else if( strcmp(tag->key, "comment") == 0 ) |
---|
1507 | m.comment = escape_tag(trim(tag->value), 1); |
---|
1508 | } |
---|
1509 | } |
---|
1510 | } |
---|
1511 | #endif |
---|
1512 | #endif |
---|
1513 | video_no_dlna: |
---|
1514 | av_close_input_file(ctx); |
---|
1515 | |
---|
1516 | #ifdef TIVO_SUPPORT |
---|
1517 | if( ends_with(path, ".TiVo") && is_tivo_file(path) ) |
---|
1518 | { |
---|
1519 | if( m.dlna_pn ) |
---|
1520 | { |
---|
1521 | free(m.dlna_pn); |
---|
1522 | m.dlna_pn = NULL; |
---|
1523 | } |
---|
1524 | m.mime = realloc(m.mime, 18); |
---|
1525 | strcpy(m.mime, "video/x-tivo-mpeg"); |
---|
1526 | } |
---|
1527 | #endif |
---|
1528 | if( !m.title ) |
---|
1529 | m.title = strdup(name); |
---|
1530 | |
---|
1531 | album_art = find_album_art(path, video.image, video.image_size); |
---|
1532 | freetags(&video); |
---|
1533 | |
---|
1534 | ret = sql_exec(db, "INSERT into DETAILS" |
---|
1535 | " (PATH, SIZE, TIMESTAMP, DURATION, DATE, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION," |
---|
1536 | " TITLE, CREATOR, ARTIST, GENRE, COMMENT, DLNA_PN, MIME, ALBUM_ART) " |
---|
1537 | "VALUES" |
---|
1538 | " (%Q, %lld, %ld, %Q, %Q, %Q, %Q, %Q, %Q, '%q', %Q, %Q, %Q, %Q, %Q, '%q', %lld);", |
---|
1539 | path, file.st_size, file.st_mtime, m.duration, |
---|
1540 | m.date, m.channels, m.bitrate, m.frequency, m.resolution, |
---|
1541 | m.title, m.creator, m.artist, m.genre, m.comment, m.dlna_pn, |
---|
1542 | m.mime, album_art); |
---|
1543 | if( ret != SQLITE_OK ) |
---|
1544 | { |
---|
1545 | fprintf(stderr, "Error inserting details for '%s'!\n", path); |
---|
1546 | ret = 0; |
---|
1547 | } |
---|
1548 | else |
---|
1549 | { |
---|
1550 | ret = sqlite3_last_insert_rowid(db); |
---|
1551 | check_for_captions(path, ret); |
---|
1552 | } |
---|
1553 | free_metadata(&m, free_flags); |
---|
1554 | |
---|
1555 | return ret; |
---|
1556 | } |
---|