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