2 * Copyright (C) 2012 Andre Noll <maan@tuebingen.mpg.de>
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 * const opus_suffixes
[] = {"opus", NULL
};
22 #define OPUS_COMMENT_HEADER "OpusTags"
24 static bool copy_if_tag_type(const char *tag
, int taglen
, const char *type
,
27 char *q
= key_value_copy(tag
, taglen
, type
);
35 static int opus_get_comments(char *comments
, int length
,
38 char *p
= comments
, *end
= comments
+ length
;
42 /* min size of a opus header is 16 bytes */
44 return -E_OPUS_COMMENT
;
45 if (memcmp(p
, OPUS_COMMENT_HEADER
, strlen(OPUS_COMMENT_HEADER
)) != 0)
46 return -E_OPUS_COMMENT
;
51 return -E_OPUS_COMMENT
;
52 tags
->comment
= safe_strdup(p
, val
);
56 if (p
+ ntags
* 4 > end
)
57 return -E_OPUS_COMMENT
;
58 PARA_INFO_LOG("found %d tag(s)\n", ntags
);
59 for (i
= 0; i
< ntags
; i
++, p
+= val
) {
63 return -E_OPUS_COMMENT
;
67 return -E_OPUS_COMMENT
;
68 if (copy_if_tag_type(p
, val
, "author", &tags
->artist
))
70 if (copy_if_tag_type(p
, val
, "artist", &tags
->artist
))
72 if (copy_if_tag_type(p
, val
, "title", &tags
->title
))
74 if (copy_if_tag_type(p
, val
, "album", &tags
->album
))
76 if (copy_if_tag_type(p
, val
, "year", &tags
->year
))
78 if (copy_if_tag_type(p
, val
, "comment", &tags
->comment
))
80 tag
= safe_strdup(p
, val
);
81 PARA_NOTICE_LOG("unrecognized tag: %s\n", tag
);
87 static int opus_packet_callback(ogg_packet
*packet
, int packet_num
,
88 __a_unused
int serial
, struct afh_info
*afhi
,
92 struct opus_header
*oh
= private_data
;
94 if (packet_num
== 0) {
95 ret
= opus_parse_header((char *)packet
->packet
, packet
->bytes
, oh
);
98 afhi
->channels
= oh
->channels
;
99 afhi
->techinfo
= make_message(
100 "header version %d, input sample rate: %" PRIu32
"Hz",
101 oh
->version
, oh
->input_sample_rate
);
103 * The input sample rate is irrelevant for afhi->frequency as
104 * we always decode to 48kHz.
106 afhi
->frequency
= 48000;
109 if (packet_num
== 1) {
110 ret
= opus_get_comments((char *)packet
->packet
, packet
->bytes
,
114 return 0; /* header complete */
120 static int opus_get_file_info(char *map
, size_t numbytes
, __a_unused
int fd
,
121 struct afh_info
*afhi
)
124 struct opus_header oh
= {.version
= 0};
126 struct ogg_afh_callback_info opus_callback_info
= {
127 .packet_callback
= opus_packet_callback
,
130 ret
= ogg_get_file_info(map
, numbytes
, afhi
, &opus_callback_info
);
133 ret
= (afhi
->chunk_table
[afhi
->chunks_total
] - afhi
->chunk_table
[0]) * 8; /* bits */
134 ms
= tv2ms(&afhi
->chunk_tv
) * afhi
->chunks_total
;
135 afhi
->bitrate
= ret
/ ms
;
139 static size_t opus_make_meta_packet(struct taginfo
*tags
, char **result
)
143 size_t comment_len
= strlen(tags
->comment
),
144 artist_len
= strlen(tags
->artist
),
145 title_len
= strlen(tags
->title
),
146 album_len
= strlen(tags
->album
),
147 year_len
= strlen(tags
->year
);
148 uint32_t comment_sz
= comment_len
,
149 artist_sz
= artist_len
+ strlen("artist="),
150 title_sz
= title_len
+ strlen("title="),
151 album_sz
= album_len
+ strlen("album="),
152 year_sz
= year_len
+ strlen("year=");
155 sz
= strlen(OPUS_COMMENT_HEADER
)
156 + 4 /* comment length (always present) */
158 + 4; /* number of tags */
176 PARA_DEBUG_LOG("meta packet size: %zu bytes\n", sz
);
177 /* terminating zero byte for the last sprintf() */
178 buf
= p
= para_malloc(sz
+ 1);
179 memcpy(p
, OPUS_COMMENT_HEADER
, strlen(OPUS_COMMENT_HEADER
));
180 p
+= strlen(OPUS_COMMENT_HEADER
);
181 write_u32(p
, comment_sz
);
183 strcpy(p
, tags
->comment
);
185 write_u32(p
, num_tags
);
188 write_u32(p
, artist_sz
);
190 sprintf(p
, "artist=%s", tags
->artist
);
194 write_u32(p
, title_sz
);
196 sprintf(p
, "title=%s", tags
->title
);
200 write_u32(p
, album_sz
);
202 sprintf(p
, "album=%s", tags
->album
);
206 write_u32(p
, year_sz
);
208 sprintf(p
, "year=%s", tags
->year
);
211 assert(p
== buf
+ sz
);
216 static int opus_rewrite_tags(const char *map
, size_t mapsize
,
217 struct taginfo
*tags
, int output_fd
,
218 __a_unused
const char *filename
)
224 meta_sz
= opus_make_meta_packet(tags
, &meta_packet
);
225 ret
= ogg_rewrite_tags(map
, mapsize
, output_fd
, meta_packet
, meta_sz
);
231 * The init function of the ogg/opus audio format handler.
233 * \param afh Pointer to the struct to initialize.
235 void opus_afh_init(struct audio_format_handler
*afh
)
237 afh
->get_file_info
= opus_get_file_info
,
238 afh
->suffixes
= opus_suffixes
;
239 afh
->rewrite_tags
= opus_rewrite_tags
;