2 * Copyright (C) 2012-2013 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file opus_afh.c Audio format handler for ogg/opus files. */
15 #include "portable_io.h"
17 #include "opus_common.h"
18 #include "ogg_afh_common.h"
20 static const char* opus_suffixes
[] = {"opus", NULL
};
22 static bool copy_if_tag_type(const char *tag
, int taglen
, const char *type
,
25 char *q
= key_value_copy(tag
, taglen
, type
);
33 static int opus_get_comments(char *comments
, int length
,
36 char *p
= comments
, *end
= comments
+ length
;
40 /* min size of a opus header is 16 bytes */
42 return -E_OPUS_COMMENT
;
43 if (memcmp(p
, "OpusTags", 8) != 0)
44 return -E_OPUS_COMMENT
;
49 return -E_OPUS_COMMENT
;
50 tags
->comment
= safe_strdup(p
, val
);
54 if (p
+ ntags
* 4 > end
)
55 return -E_OPUS_COMMENT
;
56 PARA_INFO_LOG("found %d tag(s)\n", ntags
);
57 for (i
= 0; i
< ntags
; i
++, p
+= val
) {
61 return -E_OPUS_COMMENT
;
65 return -E_OPUS_COMMENT
;
66 if (copy_if_tag_type(p
, val
, "author", &tags
->artist
))
68 if (copy_if_tag_type(p
, val
, "artist", &tags
->artist
))
70 if (copy_if_tag_type(p
, val
, "title", &tags
->title
))
72 if (copy_if_tag_type(p
, val
, "album", &tags
->album
))
74 if (copy_if_tag_type(p
, val
, "year", &tags
->year
))
76 if (copy_if_tag_type(p
, val
, "comment", &tags
->comment
))
78 tag
= safe_strdup(p
, val
);
79 PARA_NOTICE_LOG("unrecognized tag: %s\n", tag
);
85 static int opus_packet_callback(ogg_packet
*packet
, int packet_num
,
86 __a_unused
int serial
, struct afh_info
*afhi
,
90 struct opus_header
*oh
= private_data
;
92 if (packet_num
== 0) {
93 ret
= opus_parse_header((char *)packet
->packet
, packet
->bytes
, oh
);
96 afhi
->channels
= oh
->channels
;
97 afhi
->techinfo
= make_message("header version %d, input sample rate: %dHz",
98 oh
->version
, oh
->input_sample_rate
);
100 * The input sample rate is irrelevant for afhi->frequency as
101 * we always decode to 48kHz.
103 afhi
->frequency
= 48000;
106 if (packet_num
== 1) {
107 ret
= opus_get_comments((char *)packet
->packet
, packet
->bytes
,
111 return 0; /* header complete */
117 static int opus_get_file_info(char *map
, size_t numbytes
, __a_unused
int fd
,
118 struct afh_info
*afhi
)
121 struct opus_header oh
= {.version
= 0};
123 struct ogg_afh_callback_info opus_callback_info
= {
124 .packet_callback
= opus_packet_callback
,
127 ret
= ogg_get_file_info(map
, numbytes
, afhi
, &opus_callback_info
);
130 ret
= (afhi
->chunk_table
[afhi
->chunks_total
] - afhi
->chunk_table
[0]) * 8; /* bits */
131 ms
= tv2ms(&afhi
->chunk_tv
) * afhi
->chunks_total
;
132 afhi
->bitrate
= ret
/ ms
;
137 * The init function of the ogg/opus audio format handler.
139 * \param afh Pointer to the struct to initialize.
141 void opus_afh_init(struct audio_format_handler
*afh
)
143 afh
->get_file_info
= opus_get_file_info
,
144 afh
->suffixes
= opus_suffixes
;