~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/src/video/video_encoder.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2013 Savoir-Faire Linux Inc.
 
3
 *  Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 3 of the License, or
 
8
 *  (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
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
18
 *  MA  02110-1301 USA.
 
19
 *
 
20
 *  Additional permission under GNU GPL version 3 section 7:
 
21
 *
 
22
 *  If you modify this program, or any covered work, by linking or
 
23
 *  combining it with the OpenSSL project's OpenSSL library (or a
 
24
 *  modified version of that library), containing parts covered by the
 
25
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 
26
 *  grants you additional permission to convey the resulting work.
 
27
 *  Corresponding Source for a non-source form of such a combination
 
28
 *  shall include the source code for the parts of OpenSSL used as well
 
29
 *  as that of the covered work.
 
30
 */
 
31
 
 
32
#include "libav_deps.h"
 
33
#include "video_encoder.h"
 
34
#include "check.h"
 
35
 
 
36
#include <iostream>
 
37
#include <sstream>
 
38
 
 
39
 
 
40
namespace sfl_video {
 
41
 
 
42
using std::string;
 
43
 
 
44
VideoEncoder::VideoEncoder() :
 
45
    outputEncoder_(0)
 
46
    , encoderCtx_(0)
 
47
    , outputCtx_(avformat_alloc_context())
 
48
    , stream_(0)
 
49
    , scaler_()
 
50
    , scaledFrame_()
 
51
    , scaledFrameBuffer_(0)
 
52
    , scaledFrameBufferSize_(0)
 
53
    , streamIndex_(-1)
 
54
    , dstWidth_(0)
 
55
    , dstHeight_(0)
 
56
#if (LIBAVCODEC_VERSION_MAJOR < 54)
 
57
    , encoderBuffer_(0)
 
58
    , encoderBufferSize_(0)
 
59
#endif
 
60
{}
 
61
 
 
62
VideoEncoder::~VideoEncoder()
 
63
{
 
64
    if (outputCtx_ and outputCtx_->priv_data)
 
65
        av_write_trailer(outputCtx_);
 
66
 
 
67
    if (encoderCtx_)
 
68
        avcodec_close(encoderCtx_);
 
69
 
 
70
    av_free(scaledFrameBuffer_);
 
71
 
 
72
#if (LIBAVCODEC_VERSION_MAJOR < 54)
 
73
    av_free(encoderBuffer_);
 
74
#endif
 
75
}
 
76
 
 
77
int VideoEncoder::openOutput(const char *enc_name, const char *short_name,
 
78
                             const char *filename, const char *mime_type)
 
79
{
 
80
    AVOutputFormat *oformat = av_guess_format(short_name, filename,
 
81
                                              mime_type);
 
82
 
 
83
    if (!oformat) {
 
84
        ERROR("Unable to find a suitable output format for %s", filename);
 
85
        return -1;
 
86
    }
 
87
 
 
88
    outputCtx_->oformat = oformat;
 
89
    strncpy(outputCtx_->filename, filename, sizeof(outputCtx_->filename));
 
90
    // guarantee that buffer is NULL terminated
 
91
    outputCtx_->filename[sizeof(outputCtx_->filename) - 1] = '\0';
 
92
 
 
93
    /* find the video encoder */
 
94
    outputEncoder_ = avcodec_find_encoder_by_name(enc_name);
 
95
    if (!outputEncoder_) {
 
96
        ERROR("Encoder \"%s\" not found!", enc_name);
 
97
        return -1;
 
98
    }
 
99
 
 
100
    prepareEncoderContext();
 
101
 
 
102
    /* let x264 preset override our encoder settings */
 
103
    if (!strcmp(enc_name, "libx264")) {
 
104
        AVDictionaryEntry *entry = av_dict_get(options_, "parameters",
 
105
                                               NULL, 0);
 
106
        // FIXME: this should be parsed from the fmtp:profile-level-id
 
107
        // attribute of our peer, it will determine what profile and
 
108
        // level we are sending (i.e. that they can accept).
 
109
        extractProfileLevelID(entry?entry->value:"", encoderCtx_);
 
110
        forcePresetX264();
 
111
    } else if (!strcmp(enc_name, "libvpx")) {
 
112
        av_opt_set(encoderCtx_->priv_data, "quality", "realtime", 0);
 
113
    }
 
114
 
 
115
    int ret;
 
116
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 6, 0)
 
117
    ret = avcodec_open(encoderCtx_, outputEncoder_);
 
118
#else
 
119
    ret = avcodec_open2(encoderCtx_, outputEncoder_, NULL);
 
120
#endif
 
121
    if (ret) {
 
122
        ERROR("Could not open encoder");
 
123
        return -1;
 
124
    }
 
125
 
 
126
    // add video stream to outputformat context
 
127
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 8, 0)
 
128
    stream_ = av_new_stream(outputCtx_, 0);
 
129
#else
 
130
    stream_ = avformat_new_stream(outputCtx_, 0);
 
131
#endif
 
132
    if (!stream_) {
 
133
        ERROR("Could not allocate stream");
 
134
        return -1;
 
135
    }
 
136
    stream_->codec = encoderCtx_;
 
137
 
 
138
    // allocate buffers for both scaled (pre-encoder) and encoded frames
 
139
    scaledFrame_.setGeometry(encoderCtx_->width, encoderCtx_->height,
 
140
                             libav_utils::sfl_pixel_format((int)encoderCtx_->pix_fmt));
 
141
    scaledFrameBufferSize_ = scaledFrame_.getSize();
 
142
 
 
143
    if (scaledFrameBufferSize_ <= FF_MIN_BUFFER_SIZE) {
 
144
        ERROR(" buffer too small");
 
145
        return -1;
 
146
    }
 
147
 
 
148
#if (LIBAVCODEC_VERSION_MAJOR < 54)
 
149
    encoderBufferSize_ = scaledFrameBufferSize_; // seems to be ok
 
150
    encoderBuffer_ = (uint8_t*) av_malloc(encoderBufferSize_);
 
151
    if (!encoderBuffer_) {
 
152
        ERROR("encoderBuffer = av_malloc() failed");
 
153
        return -1;
 
154
    }
 
155
#endif
 
156
 
 
157
    scaledFrameBuffer_ = (uint8_t*) av_malloc(scaledFrameBufferSize_);
 
158
    if (!scaledFrameBuffer_) {
 
159
        ERROR("scaledFrameBuffer = av_malloc() failed");
 
160
        return -1;
 
161
    }
 
162
 
 
163
    scaledFrame_.setDestination(scaledFrameBuffer_);
 
164
 
 
165
    return 0;
 
166
}
 
167
 
 
168
void VideoEncoder::setInterruptCallback(int (*cb)(void*), void *opaque)
 
169
{
 
170
    if (cb) {
 
171
        outputCtx_->interrupt_callback.callback = cb;
 
172
        outputCtx_->interrupt_callback.opaque = opaque;
 
173
    } else {
 
174
        outputCtx_->interrupt_callback.callback = 0;
 
175
    }
 
176
}
 
177
 
 
178
void VideoEncoder::setIOContext(const std::unique_ptr<VideoIOHandle> &ioctx)
 
179
{
 
180
    outputCtx_->pb = ioctx->getContext();
 
181
    outputCtx_->packet_size = outputCtx_->pb->buffer_size;
 
182
}
 
183
 
 
184
int VideoEncoder::startIO()
 
185
{
 
186
    int ret = avformat_write_header(outputCtx_,
 
187
                                    options_ ? &options_ : NULL);
 
188
    if (ret) {
 
189
        ERROR("Could not write header for output file..."
 
190
              "check codec parameters");
 
191
        return -1;
 
192
    }
 
193
 
 
194
    av_dump_format(outputCtx_, 0, outputCtx_->filename, 1);
 
195
 
 
196
    return 0;
 
197
}
 
198
 
 
199
int VideoEncoder::encode(VideoFrame &input, bool is_keyframe, int frame_number)
 
200
{
 
201
    int ret;
 
202
    AVFrame *frame = scaledFrame_.get();
 
203
 
 
204
    scaler_.scale(input, scaledFrame_);
 
205
    frame->pts = frame_number;
 
206
 
 
207
    if (is_keyframe) {
 
208
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(53, 20, 0)
 
209
        frame->pict_type = AV_PICTURE_TYPE_I;
 
210
#else
 
211
        frame->pict_type = FF_I_TYPE;
 
212
#endif
 
213
    } else {
 
214
        /* FIXME: Should be AV_PICTURE_TYPE_NONE for newer libavutil */
 
215
        frame->pict_type = (AVPictureType) 0;
 
216
    }
 
217
 
 
218
    AVPacket pkt = {};
 
219
    av_init_packet(&pkt);
 
220
 
 
221
#if (LIBAVCODEC_VERSION_MAJOR >= 54)
 
222
    int got_packet;
 
223
    ret = avcodec_encode_video2(encoderCtx_, &pkt, frame, &got_packet);
 
224
    if (ret != 0) {
 
225
        ERROR("avcodec_encode_video2 failed");
 
226
        av_free_packet(&pkt);
 
227
        return -1;
 
228
    }
 
229
 
 
230
    if (pkt.size and got_packet) {
 
231
        if (pkt.pts != AV_NOPTS_VALUE)
 
232
            pkt.pts = av_rescale_q(pkt.pts, encoderCtx_->time_base, stream_->time_base);
 
233
        if (pkt.dts != AV_NOPTS_VALUE)
 
234
            pkt.dts = av_rescale_q(pkt.dts, encoderCtx_->time_base, stream_->time_base);
 
235
 
 
236
        pkt.stream_index = stream_->index;
 
237
 
 
238
        // write the compressed frame
 
239
        ret = av_interleaved_write_frame(outputCtx_, &pkt);
 
240
        if (ret)
 
241
            ERROR("interleaved_write_frame failed");
 
242
    }
 
243
 
 
244
#else
 
245
    ret = avcodec_encode_video(encoderCtx_, encoderBuffer_,
 
246
                               encoderBufferSize_, frame);
 
247
    if (ret < 0) {
 
248
        ERROR("avcodec_encode_video failed");
 
249
        av_free_packet(&pkt);
 
250
        return ret;
 
251
    }
 
252
 
 
253
    pkt.data = encoderBuffer_;
 
254
    pkt.size = ret;
 
255
 
 
256
    // rescale pts from encoded video framerate to rtp clock rate
 
257
    if (encoderCtx_->coded_frame->pts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
 
258
        pkt.pts = av_rescale_q(encoderCtx_->coded_frame->pts,
 
259
                encoderCtx_->time_base, stream_->time_base);
 
260
     } else {
 
261
         pkt.pts = 0;
 
262
     }
 
263
 
 
264
     // is it a key frame?
 
265
     if (encoderCtx_->coded_frame->key_frame)
 
266
         pkt.flags |= AV_PKT_FLAG_KEY;
 
267
     pkt.stream_index = stream_->index;
 
268
 
 
269
    // write the compressed frame
 
270
     if ((ret = av_interleaved_write_frame(outputCtx_, &pkt)) < 0)
 
271
         ERROR("interleaved_write_frame failed");
 
272
 
 
273
#endif
 
274
     av_free_packet(&pkt);
 
275
 
 
276
     return ret;
 
277
}
 
278
 
 
279
int VideoEncoder::flush()
 
280
{
 
281
    AVPacket pkt = {};
 
282
    av_init_packet(&pkt);
 
283
 
 
284
    int ret;
 
285
#if (LIBAVCODEC_VERSION_MAJOR >= 54)
 
286
 
 
287
    int got_packet;
 
288
 
 
289
    ret = avcodec_encode_video2(encoderCtx_, &pkt, NULL, &got_packet);
 
290
    if (ret != 0) {
 
291
        ERROR("avcodec_encode_video failed");
 
292
        av_free_packet(&pkt);
 
293
        return -1;
 
294
    }
 
295
 
 
296
    if (pkt.size and got_packet) {
 
297
        // write the compressed frame
 
298
        ret = av_interleaved_write_frame(outputCtx_, &pkt);
 
299
        if (ret < 0)
 
300
            ERROR("interleaved_write_frame failed");
 
301
    }
 
302
#else
 
303
    ret = avcodec_encode_video(encoderCtx_, encoderBuffer_,
 
304
                               encoderBufferSize_, NULL);
 
305
    if (ret < 0) {
 
306
        ERROR("avcodec_encode_video failed");
 
307
        av_free_packet(&pkt);
 
308
        return ret;
 
309
    }
 
310
 
 
311
    pkt.data = encoderBuffer_;
 
312
    pkt.size = ret;
 
313
 
 
314
    // write the compressed frame
 
315
    ret = av_interleaved_write_frame(outputCtx_, &pkt);
 
316
    if (ret < 0)
 
317
        ERROR("interleaved_write_frame failed");
 
318
#endif
 
319
    av_free_packet(&pkt);
 
320
 
 
321
    return ret;
 
322
}
 
323
 
 
324
void VideoEncoder::print_sdp(std::string &sdp_)
 
325
{
 
326
    /* theora sdp can be huge */
 
327
    const size_t sdp_size = outputCtx_->streams[0]->codec->extradata_size \
 
328
        + 2048;
 
329
    std::string sdp(sdp_size, 0);
 
330
    av_sdp_create(&outputCtx_, 1, &(*sdp.begin()), sdp_size);
 
331
    std::istringstream iss(sdp);
 
332
    string line;
 
333
    sdp_ = "";
 
334
    while (std::getline(iss, line)) {
 
335
        /* strip windows line ending */
 
336
        line = line.substr(0, line.length() - 1);
 
337
        sdp_ += line + "\n";
 
338
    }
 
339
    DEBUG("Sending SDP: \n%s", sdp_.c_str());
 
340
}
 
341
 
 
342
void VideoEncoder::prepareEncoderContext()
 
343
{
 
344
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 12, 0)
 
345
    encoderCtx_ = avcodec_alloc_context();
 
346
    avcodec_get_context_defaults(encoderCtx_);
 
347
    (void) outputEncoder_;
 
348
#else
 
349
    encoderCtx_ = avcodec_alloc_context3(outputEncoder_);
 
350
#endif
 
351
 
 
352
    // set some encoder settings here
 
353
    encoderCtx_->bit_rate = 1000 * atoi(av_dict_get(options_, "bitrate",
 
354
                                                    NULL, 0)->value);
 
355
    DEBUG("Using bitrate %d", encoderCtx_->bit_rate);
 
356
 
 
357
    // resolution must be a multiple of two
 
358
    char *width = av_dict_get(options_, "width", NULL, 0)->value;
 
359
    dstWidth_ = encoderCtx_->width = width ? atoi(width) : 0;
 
360
    char *height = av_dict_get(options_, "height", NULL, 0)->value;
 
361
    dstHeight_ = encoderCtx_->height = height ? atoi(height) : 0;
 
362
 
 
363
    const char *framerate = av_dict_get(options_, "framerate",
 
364
                                        NULL, 0)->value;
 
365
    const int DEFAULT_FPS = 30;
 
366
    const int fps = framerate ? atoi(framerate) : DEFAULT_FPS;
 
367
    encoderCtx_->time_base = (AVRational) {1, fps};
 
368
    // emit one intra frame every gop_size frames
 
369
    encoderCtx_->max_b_frames = 0;
 
370
    encoderCtx_->pix_fmt = PIXEL_FORMAT(YUV420P); // TODO: option me !
 
371
 
 
372
    // Fri Jul 22 11:37:59 EDT 2011:tmatth:XXX: DON'T set this, we want our
 
373
    // pps and sps to be sent in-band for RTP
 
374
    // This is to place global headers in extradata instead of every
 
375
    // keyframe.
 
376
    // encoderCtx_->flags |= CODEC_FLAG_GLOBAL_HEADER;
 
377
}
 
378
 
 
379
void VideoEncoder::forcePresetX264()
 
380
{
 
381
    const char *speedPreset = "ultrafast";
 
382
    if (av_opt_set(encoderCtx_->priv_data, "preset", speedPreset, 0))
 
383
        WARN("Failed to set x264 preset '%s'", speedPreset);
 
384
    const char *tune = "zerolatency";
 
385
    if (av_opt_set(encoderCtx_->priv_data, "tune", tune, 0))
 
386
        WARN("Failed to set x264 tune '%s'", tune);
 
387
}
 
388
 
 
389
void VideoEncoder::extractProfileLevelID(const std::string &parameters,
 
390
                                         AVCodecContext *ctx)
 
391
{
 
392
    // From RFC3984:
 
393
    // If no profile-level-id is present, the Baseline Profile without
 
394
    // additional constraints at Level 1 MUST be implied.
 
395
    ctx->profile = FF_PROFILE_H264_BASELINE;
 
396
    ctx->level = 0x0d;
 
397
    // ctx->level = 0x0d; // => 13 aka 1.3
 
398
    if (parameters.empty())
 
399
        return;
 
400
 
 
401
    const std::string target("profile-level-id=");
 
402
    size_t needle = parameters.find(target);
 
403
    if (needle == std::string::npos)
 
404
        return;
 
405
 
 
406
    needle += target.length();
 
407
    const size_t id_length = 6; /* digits */
 
408
    const std::string profileLevelID(parameters.substr(needle, id_length));
 
409
    if (profileLevelID.length() != id_length)
 
410
        return;
 
411
 
 
412
    int result;
 
413
    std::stringstream ss;
 
414
    ss << profileLevelID;
 
415
    ss >> std::hex >> result;
 
416
    // profile-level id consists of three bytes
 
417
    const unsigned char profile_idc = result >> 16;             // 42xxxx -> 42
 
418
    const unsigned char profile_iop = ((result >> 8) & 0xff);   // xx80xx -> 80
 
419
    ctx->level = result & 0xff;                                 // xxxx0d -> 0d
 
420
    switch (profile_idc) {
 
421
                case FF_PROFILE_H264_BASELINE:
 
422
                        // check constraint_set_1_flag
 
423
                        if ((profile_iop & 0x40) >> 6)
 
424
                                ctx->profile |= FF_PROFILE_H264_CONSTRAINED;
 
425
                        break;
 
426
                case FF_PROFILE_H264_HIGH_10:
 
427
                case FF_PROFILE_H264_HIGH_422:
 
428
                case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
 
429
                        // check constraint_set_3_flag
 
430
                        if ((profile_iop & 0x10) >> 4)
 
431
                                ctx->profile |= FF_PROFILE_H264_INTRA;
 
432
                        break;
 
433
    }
 
434
    DEBUG("Using profile %x and level %d", ctx->profile, ctx->level);
 
435
}
 
436
 
 
437
}