* Add code to pace sending a stream when it is being sent from a file.
[ffmpeg.git] / libav / ogg.c
1 /*
2  * Ogg bitstream support
3  * Mark Hills <mark@pogo.org.uk>
4  *
5  * Uses libogg, but requires libvorbisenc to construct correct headers
6  * when containing Vorbis stream -- currently the only format supported
7  */
8
9 #include <stdio.h>
10 #include <time.h>
11
12 #include <ogg/ogg.h>
13 #include <vorbis/vorbisenc.h>
14
15 #include "avformat.h"
16 #include "oggvorbis.h"
17
18
19 typedef struct OggContext {
20     ogg_stream_state os ;
21     int header_written ;
22     ogg_int64_t base_packet_no ;
23     ogg_int64_t base_granule_pos ;
24 } OggContext ;
25
26
27 static int ogg_write_header(AVFormatContext *avfcontext) {
28     OggContext *context ;
29     AVCodecContext *avccontext ;
30     vorbis_info vi ;
31     vorbis_dsp_state vd ;
32     vorbis_comment vc ;
33     vorbis_block vb ;
34     ogg_packet header, header_comm, header_code ; 
35     int n ;
36     
37     fprintf(stderr, "ogg_write_header\n") ;
38     
39     if(!(context = malloc(sizeof(OggContext))))
40         return -1 ;
41     avfcontext->priv_data = context ;
42     
43     srand(time(NULL));
44     ogg_stream_init(&context->os, rand());
45     
46     for(n = 0 ; n < avfcontext->nb_streams ; n++) {
47         avccontext = &avfcontext->streams[n]->codec ;
48
49         /* begin vorbis specific code */
50                 
51         vorbis_info_init(&vi) ;
52
53         /* code copied from libavcodec/oggvorbis.c */
54
55         if(oggvorbis_init_encoder(&vi, avccontext) < 0) {
56             fprintf(stderr, "ogg_write_header: init_encoder failed") ;
57             return -1 ;
58         }
59
60         vorbis_analysis_init(&vd, &vi) ;
61         vorbis_block_init(&vd, &vb) ;
62         
63         vorbis_comment_init(&vc) ;
64         vorbis_comment_add_tag(&vc, "encoder", "ffmpeg") ;
65         if(*avfcontext->title)
66             vorbis_comment_add_tag(&vc, "title", avfcontext->title) ;
67
68         vorbis_analysis_headerout(&vd, &vc, &header,
69                                   &header_comm, &header_code) ;
70         ogg_stream_packetin(&context->os, &header) ;
71         ogg_stream_packetin(&context->os, &header_comm) ;
72         ogg_stream_packetin(&context->os, &header_code) ;  
73         
74         vorbis_comment_clear(&vc) ;
75
76         /* end of vorbis specific code */
77
78         context->header_written = 0 ;
79         context->base_packet_no = 0 ;
80     }
81     
82     return 0 ;
83 }
84
85
86 static int ogg_write_packet(AVFormatContext *avfcontext,
87                             int stream_index,
88                             unsigned char *buf, int size, int force_pts)
89 {
90     OggContext *context = avfcontext->priv_data ;
91     ogg_packet *op ;
92     ogg_page og ;
93     int l = 0 ;
94     
95     /* flush header packets so audio starts on a new page */
96
97     if(!context->header_written) {
98         while(ogg_stream_flush(&context->os, &og)) {
99             put_buffer(&avfcontext->pb, og.header, og.header_len) ;
100             put_buffer(&avfcontext->pb, og.body, og.body_len) ;
101             put_flush_packet(&avfcontext->pb);
102         }
103         context->header_written = 1 ;
104     }
105
106     while(l < size) {
107         op = (ogg_packet*)(buf + l) ;
108         op->packet = buf + l + sizeof(ogg_packet) ; /* fix data pointer */
109
110         if(!context->base_packet_no) { /* this is the first packet */
111             context->base_packet_no = op->packetno ; 
112             context->base_granule_pos = op->granulepos ;
113         }
114
115         /* correct the fields in the packet -- essential for streaming */
116
117         op->packetno -= context->base_packet_no ;
118         op->granulepos -= context->base_granule_pos ;
119
120         ogg_stream_packetin(&context->os, op) ;
121         l += sizeof(ogg_packet) + op->bytes ;
122
123         while(ogg_stream_pageout(&context->os, &og)) {
124             put_buffer(&avfcontext->pb, og.header, og.header_len) ;
125             put_buffer(&avfcontext->pb, og.body, og.body_len) ;
126             put_flush_packet(&avfcontext->pb);
127         }
128     }
129
130     return 0;
131 }
132
133
134 static int ogg_write_trailer(AVFormatContext *avfcontext) {
135     OggContext *context = avfcontext->priv_data ;
136     ogg_page og ;
137
138     fprintf(stderr, "ogg_write_trailer\n") ;
139
140     while(ogg_stream_flush(&context->os, &og)) {
141         put_buffer(&avfcontext->pb, og.header, og.header_len) ;
142         put_buffer(&avfcontext->pb, og.body, og.body_len) ;
143         put_flush_packet(&avfcontext->pb);
144     }
145
146     ogg_stream_clear(&context->os) ;
147     return 0 ;
148 }
149
150
151 AVOutputFormat ogg_oformat = {
152     "ogg",
153     "Ogg Vorbis",
154     "audio/x-vorbis",
155     "ogg",
156     sizeof(OggContext),
157     CODEC_ID_VORBIS,
158     0,
159     ogg_write_header,
160     ogg_write_packet,
161     ogg_write_trailer,
162 };
163
164
165 int ogg_init(void) {
166     av_register_output_format(&ogg_oformat) ;
167     return 0 ;
168 }