Mercurial > projects > hoofbaby
comparison src/impl/hoofbaby/codec/encoder.d @ 4:a1202aac1124
Started implementing separate encoder class
author | fraserofthenight |
---|---|
date | Wed, 08 Jul 2009 19:16:39 -0700 |
parents | |
children | 270343d824ae |
comparison
equal
deleted
inserted
replaced
3:e6cf9f26d0e7 | 4:a1202aac1124 |
---|---|
1 /** | |
2 * Hoofbaby -- http://www.dsource.org/projects/hoofbaby | |
3 * Copyright (C) 2009 Robert Fraser | |
4 * | |
5 * This program is free software; you can redistribute it andor | |
6 * modify it under the terms of the GNU General Public License | |
7 * as published by the Free Software Foundation; either version 2 | |
8 * of the License, or (at your option) any later version. | |
9 * | |
10 * This program 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 | |
16 module hoofbaby.codec.encoder; | |
17 | |
18 import hoofbaby.codec.libav.avutil; | |
19 import hoofbaby.codec.libav.avcodec; | |
20 import hoofbaby.codec.libav.avformat; | |
21 | |
22 public final class Encoder | |
23 { | |
24 // TODO convert asserts to exceptions | |
25 | |
26 private const int OUTBUF_SIZE = 100000; | |
27 | |
28 private AVOutputFormat* format; | |
29 private AVFormatContext* formatContext; | |
30 | |
31 private AVCodec* audioCodec; | |
32 private AVCodecContext* audioContext; | |
33 private AVStream* audioStream; | |
34 private char* audioOutbuf; | |
35 | |
36 private AVCodec* videoCodec; | |
37 private AVCodecContext* videoContext; | |
38 private AVStream* videoStream; | |
39 private char* videoOutbuf; | |
40 | |
41 public this() | |
42 { | |
43 int ret; // Stores return value of functions called within | |
44 | |
45 //-------------------------------------------------------------------------- | |
46 // Container format | |
47 | |
48 format = guess_format("asf", null, null); | |
49 assert(format !is null, "Could not find format"); | |
50 | |
51 formatContext = av_alloc_format_context(); | |
52 assert(formatContext !is null, "Could not allocate format context"); | |
53 res.add(formatContext, &av_free); | |
54 formatContext.oformat = fmt; | |
55 //ctx.preload = cast(int) (0.5 * AV_TIME_BASE); | |
56 formatContext.max_delay = cast(int) (0.7 * AV_TIME_BASE); | |
57 formatContext.loop_output = AVFMT_NOOUTPUTLOOP; | |
58 formatContext.flags |= AVFMT_FLAG_NONBLOCK; | |
59 | |
60 AVFormatParameters params; | |
61 params.prealloced_context = 1; | |
62 params.video_codec_id = CODEC_ID_WMV2; | |
63 params.audio_codec_id = CODEC_ID_WMAV2; | |
64 params.width = 352; // TEMP | |
65 params.height = 288; // TEMP | |
66 params.time_base.num = 1; // TEMP | |
67 params.time_base.den = 25; // TEMP | |
68 params.pix_fmt = PIX_FMT_YUV420P; | |
69 params.channels = 2; // NEXTVERSION support >2 channels for devices that can handle it | |
70 params.sample_rate = 44100; // TEMP | |
71 ret = av_set_parameters(formatContext, null); | |
72 assert(ret >= 0, "Could not set parameters"); | |
73 | |
74 //-------------------------------------------------------------------------- | |
75 // Video stream | |
76 | |
77 videoStream = av_new_stream(formatContext, 0); | |
78 assert(videoStream !is null, "Could not allocate video stream"); | |
79 formatContext.streams[0] = vstream; | |
80 | |
81 videoCodec = avcodec_find_encoder(CODEC_ID_WMV2); | |
82 assert(videoCodec !is null, "Could not find video codec"); | |
83 | |
84 videoContext = videoStream.codec; | |
85 videoContext.codec_id = CODEC_ID_WMV2; | |
86 videoContext.codec_type = CODEC_TYPE_VIDEO; | |
87 videoContext.bit_rate = 400000; //TEMP | |
88 videoContext.width = 352; // TEMP | |
89 videoContext.height = 288; // TEMP | |
90 videoContext.gop_size = 12; // TEMP | |
91 videoContext.qmin = 3; // TEMP | |
92 videoContext.time_base.den = 25; // TEMP | |
93 videoContext.time_base.num = 1; // TEMP | |
94 videoContext.pix_fmt = PIX_FMT_YUV420P; | |
95 videoContext.flags |= CODEC_FLAG_GLOBAL_HEADER; | |
96 ret = avcodec_open(videoContext, videoCodec); | |
97 assert(ret >= 0, "Could not open video codec"); | |
98 | |
99 videoOutbuf = cast(char*) av_malloc(OUTBUF_SIZE); | |
100 assert(videoOutbuf !is null, "Could not allocate video output buffer"); | |
101 | |
102 //-------------------------------------------------------------------------- | |
103 // Audio stream | |
104 | |
105 audioStream = av_new_stream(formatContext, 0); | |
106 assert(audioStream !is null, "Could not allocate audio stream"); | |
107 formatContext.streams[1] = audioStream; | |
108 | |
109 audioCodec = avcodec_find_encoder(CODEC_ID_WMAV2); | |
110 assert(audioCodec !is null, "Could not find audio codec"); | |
111 | |
112 audioContext = audioStream.codec; | |
113 audioContext.codec_id = CODEC_ID_WMAV2; | |
114 audioContext.codec_type = CODEC_TYPE_AUDIO; | |
115 audioContext.bit_rate = 64000; | |
116 audioContext.sample_rate = 44100; | |
117 audioContext.channels = 2; | |
118 audioContext.flags |= CODEC_FLAG_GLOBAL_HEADER; | |
119 ret = avcodec_open(audioContext, audioCodec); | |
120 assert(res >= 0, "Could not open audio codec"); | |
121 | |
122 audioOutbuf = cast(char*) av_malloc(OUTBUF_SIZE); | |
123 assert(audioOutbuf !is null, "Could not allocate audio output buffer"); | |
124 | |
125 scope(failure) | |
126 { | |
127 freeResources(); | |
128 } | |
129 } | |
130 | |
131 public ~this() | |
132 { | |
133 freeResources(); | |
134 } | |
135 | |
136 public void writeHeader() | |
137 { | |
138 int ret = av_write_header(formatContext); | |
139 assert(ret >= 0, "Could not write header for output file (incorrect codec paramters?)"); | |
140 } | |
141 | |
142 public void writeTrailer() | |
143 { | |
144 int ret = av_write_trailer(ctx); | |
145 assert(ret >= 0, "Could not write trailer for output file"); | |
146 } | |
147 | |
148 public void writeVideoFrame(AVFrame* frame) | |
149 { | |
150 int outSize = avcodec_encode_video(videoCodec, videoOutbuf, OUTBUF_SIZE, frame); | |
151 | |
152 // if zero size, it means the image was buffered, so don't write the packet | |
153 if(outSize > 0) | |
154 { | |
155 AVPacket pkt; | |
156 av_init_packet(&pkt); | |
157 pkt.pts = av_rescale_q(videoCodec.coded_frame.pts, videoCodec.time_base, videoStream.time_base); | |
158 if(videoCodec.coded_frame.key_frame) | |
159 pkt.flags |= PKT_FLAG_KEY; | |
160 pkt.stream_index = videoStream.index; | |
161 pkt.data = videoOutbuf; | |
162 pkt.size = outSize; | |
163 int ret = av_write_frame(ctx, &pkt); | |
164 assert(!ret, "Error writing video frame"); | |
165 } | |
166 } | |
167 | |
168 public void writeAudioFrame(short* samples) | |
169 { | |
170 AVPacket pkt; | |
171 av_init_packet(&pkt); | |
172 pkt.size = avcodec_encode_audio(audioCodec, audioOutbuf, OUTBUF_SIZE, samples); | |
173 //pkt.pts = av_rescale_q(acodec.coded_frame.pts, acodec.time_base, acodec.time_base); | |
174 pkt.flags |= PKT_FLAG_KEY; | |
175 pkt.stream_index = audioStream.index; | |
176 pkt.data = audioOutbuf; | |
177 int ret = av_write_frame(ctx, &pkt) != 0; | |
178 assert(ret == 0, "Error writing audio frame"); | |
179 } | |
180 | |
181 private void freeResources() | |
182 { | |
183 if(formatContext) av_free(formatContext); | |
184 if(audioOutbuf) av_free(audioOutbuf); | |
185 if(videoOutbuf) av_free(videoOutbuf); | |
186 } | |
187 } |