2 * Copyright (C) 2004-2011 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file ogg_afh.c Audio format handler for ogg/vorbis files. */
9 #include <vorbis/codec.h>
16 #include "ogg_afh_common.h"
18 struct private_vorbis_data
{
23 static int vorbis_packet_callback(ogg_packet
*packet
, int packet_num
,
24 __a_unused
int serial
, struct afh_info
*afhi
, void *private_data
)
26 struct private_vorbis_data
*pvd
= private_data
;
28 if (vorbis_synthesis_headerin(&pvd
->vi
, &pvd
->vc
, packet
) < 0)
30 if (packet_num
== 0) {
31 if (pvd
->vi
.rate
== 0)
33 afhi
->channels
= pvd
->vi
.channels
;
34 afhi
->frequency
= pvd
->vi
.rate
;
35 afhi
->bitrate
= pvd
->vi
.bitrate_nominal
/ 1000;
36 PARA_DEBUG_LOG("channels: %i, sampling rate: %i, bitrate: %i\n",
37 afhi
->channels
, afhi
->frequency
, afhi
->bitrate
);
41 return 1; /* we also want to have packet #2 */
42 afhi
->tags
.artist
= para_strdup(vorbis_comment_query(&pvd
->vc
, "artist", 0));
43 afhi
->tags
.title
= para_strdup(vorbis_comment_query(&pvd
->vc
, "title", 0));
44 afhi
->tags
.album
= para_strdup(vorbis_comment_query(&pvd
->vc
, "album", 0));
45 afhi
->tags
.year
= para_strdup(vorbis_comment_query(&pvd
->vc
, "year", 0));
46 afhi
->tags
.comment
= para_strdup(vorbis_comment_query(&pvd
->vc
, "comment", 0));
50 static int ogg_vorbis_get_file_info(char *map
, size_t numbytes
, __a_unused
int fd
,
51 struct afh_info
*afhi
)
54 struct private_vorbis_data pvd
;
55 struct ogg_afh_callback_info vorbis_callback_info
= {
56 .packet_callback
= vorbis_packet_callback
,
60 vorbis_info_init(&pvd
.vi
);
61 vorbis_comment_init(&pvd
.vc
);
62 ret
= ogg_get_file_info(map
, numbytes
, afhi
, &vorbis_callback_info
);
63 vorbis_info_clear(&pvd
.vi
);
64 vorbis_comment_clear(&pvd
.vc
);
68 struct vorbis_get_header_data
{
74 static void add_ogg_page(ogg_page
*og
, struct vorbis_get_header_data
*vghd
)
76 size_t old_len
= vghd
->len
;
77 size_t new_len
= vghd
->len
+ og
->header_len
+ og
->body_len
;
78 char *buf
= para_realloc(vghd
->buf
, new_len
), *p
= buf
+ old_len
;
80 memcpy(p
, og
->header
, og
->header_len
);
81 memcpy(p
+ og
->header_len
, og
->body
, og
->body_len
);
84 PARA_DEBUG_LOG("header/body/old/new: %lu/%lu/%zu/%zu\n",
85 og
->header_len
, og
->body_len
, old_len
, new_len
);
88 static int vorbis_get_header_callback(ogg_packet
*packet
, int packet_num
,
89 int serial
, __a_unused
struct afh_info
*afhi
, void *private_data
)
92 struct vorbis_get_header_data
*vghd
= private_data
;
94 static unsigned char dummy_packet
[] = {
96 'v', 'o', 'r', 'b', 'i', 's',
97 0x06, 0x00, 0x00, 0x00,
98 'd', 'u', 'm', 'm', 'y', '\0',
99 0x00, 0x00, 0x00, 0x00, /* no comment :) */
100 0xff /* framing bit */
103 PARA_DEBUG_LOG("processing ogg packet #%d\n", packet_num
);
106 if (packet_num
== 0) {
107 ogg_stream_init(&vghd
->os
, serial
);
108 ret
= -E_OGG_PACKET_IN
;
109 ret
= ogg_stream_packetin(&vghd
->os
, packet
);
112 ret
= -E_OGG_STREAM_FLUSH
;
113 if (ogg_stream_flush(&vghd
->os
, &og
) == 0)
115 add_ogg_page(&og
, vghd
);
118 if (packet_num
== 1) {
119 PARA_INFO_LOG("replacing metadata packet\n");
120 ogg_packet replacement
= *packet
;
121 replacement
.packet
= dummy_packet
;
122 replacement
.bytes
= sizeof(dummy_packet
);
123 ret
= ogg_stream_packetin(&vghd
->os
, &replacement
);
126 ret
= -E_OGG_PACKET_IN
;
129 ret
= -E_OGG_PACKET_IN
;
130 if (ogg_stream_packetin(&vghd
->os
, packet
) < 0)
132 ret
= -E_OGG_STREAM_FLUSH
;
133 if (ogg_stream_flush(&vghd
->os
, &og
) == 0)
135 add_ogg_page(&og
, vghd
);
138 ogg_stream_clear(&vghd
->os
);
142 static void vorbis_get_header(void *map
, size_t mapsize
, char **buf
,
146 struct vorbis_get_header_data vghd
= {.len
= 0};
147 struct ogg_afh_callback_info cb
= {
148 .packet_callback
= vorbis_get_header_callback
,
149 .private_data
= &vghd
,
152 ret
= ogg_get_file_info(map
, mapsize
, NULL
, &cb
);
157 PARA_INFO_LOG("created %zu byte ogg vorbis header\n", *len
);
160 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
163 static const char* ogg_suffixes
[] = {"ogg", NULL
};
166 * The init function of the ogg vorbis audio format handler.
168 * \param afh Pointer to the struct to initialize.
170 void ogg_init(struct audio_format_handler
*afh
)
172 afh
->get_file_info
= ogg_vorbis_get_file_info
;
173 afh
->get_header
= vorbis_get_header
;
174 afh
->suffixes
= ogg_suffixes
;