~phablet-team/aethercast/fix-for-microsoft-dongle

« back to all changes in this revision

Viewing changes to src/mcs/android/h264encoder.cpp

Add hardware encoding and video streaming support.

The hardware encoding is currently only for Android 5.x based devices. On all others encoding will simply not work. The streaming part of aethercast (MPEGTS packetizing, RTP sending) as based on some code from Android.

Approved by PS Jenkins bot, Thomas Voß, Jim Hodapp.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2016 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3, as published
 
6
 * by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
 * PURPOSE.  See the GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 */
 
17
 
 
18
// Ignore all warnings coming from the external Android headers as
 
19
// we don't control them and also don't want to get any warnings
 
20
// from them which will only polute our build output.
 
21
#pragma GCC diagnostic push
 
22
#pragma GCC diagnostic warning "-w"
 
23
#include <system/window.h>
 
24
#pragma GCC diagnostic pop
 
25
 
 
26
#include <boost/concept_check.hpp>
 
27
 
 
28
#include "mcs/logger.h"
 
29
#include "mcs/keep_alive.h"
 
30
 
 
31
#include "mcs/video/statistics.h"
 
32
 
 
33
#include "mcs/android/h264encoder.h"
 
34
 
 
35
namespace {
 
36
static constexpr const char *kEncoderThreadName{"H264Encoder"};
 
37
static constexpr const char *kH264MimeType{"video/avc"};
 
38
static constexpr const char *kRawMimeType{"video/raw"};
 
39
// From frameworks/native/include/media/openmax/OMX_IVCommon.h
 
40
static constexpr int32_t kOMXColorFormatAndroidOpaque = 0x7F000789;
 
41
static constexpr int32_t kOMXVideoIntraRefreshCyclic = 0;
 
42
// From frameworks/native/include/media/openmax/OMX_Video.h
 
43
static constexpr int32_t kOMXVideoControlRateConstant = 2;
 
44
// From frameworks/native/include/media/hardware/MetadataBufferType.h
 
45
static constexpr uint32_t kMetadataBufferTypeGrallocSource = 1;
 
46
// Supplying -1 as framerate means the encoder decides on which framerate
 
47
// it provides.
 
48
static constexpr int32_t kAnyFramerate = -1;
 
49
// Default is a bitrate of 5 MBit/s
 
50
static constexpr int32_t kDefaultBitrate = 5000000;
 
51
// By default send an I frame every 15 seconds which is the
 
52
// same Android currently configures in its WiFi Display code path.
 
53
static constexpr std::chrono::seconds kDefaultIFrameInterval{15};
 
54
// From frameworks/av/include/media/stagefright/MediaErrors.h
 
55
enum AndroidMediaError {
 
56
    kAndroidMediaErrorBase = -1000,
 
57
    kAndroidMediaErrorNotConnected = kAndroidMediaErrorBase - 1,
 
58
    kAndroidMediaErrorBufferTooSmall = kAndroidMediaErrorBase - 9,
 
59
    kAndroidMediaErrorEndOfStream = kAndroidMediaErrorBase - 11,
 
60
};
 
61
// Constants for all the fields we're putting into the AMessage
 
62
// structure to configure the MediaCodec instance for our needs.
 
63
static constexpr const char *kFormatKeyMime{"mime"};
 
64
static constexpr const char *kFormatKeyStoreMetaDataInBuffers{"store-metadata-in-buffers"};
 
65
static constexpr const char *kFormatKeyStoreMetaDataInBuffersOutput{"store-metadata-in-buffers-output"};
 
66
static constexpr const char *kFormatKeyWidth{"width"};
 
67
static constexpr const char *kFormatKeyHeight{"height"};
 
68
static constexpr const char *kFormatKeyStride{"stride"};
 
69
static constexpr const char *kFormatKeySliceHeight{"slice-height"};
 
70
static constexpr const char *kFormatKeyColorFormat{"color-format"};
 
71
static constexpr const char *kFormatKeyBitrate{"bitrate"};
 
72
static constexpr const char *kFormatKeyBitrateMode{"bitrate-mode"};
 
73
static constexpr const char *kFormatKeyFramerate{"frame-rate"};
 
74
static constexpr const char *kFormatKeyIntraRefreshMode{"intra-refresh-mode"};
 
75
static constexpr const char *kFormatKeyIntraRefreshCIRMbs{"intra-refresh-CIR-mbs"};
 
76
static constexpr const char *kFormatKeyIFrameInterval{"i-frame-interval"};
 
77
static constexpr const char *kFormatKeyProfileIdc{"profile-idc"};
 
78
static constexpr const char *kFormatKeyLevelIdc{"level-idc"};
 
79
static constexpr const char *kFormatKeyConstraintSet{"constraint-set"};
 
80
static constexpr const char *kFormatKeyPrependSpsPpstoIdrFrames{"prepend-sps-pps-to-idr-frames"};
 
81
}
 
82
 
 
83
namespace mcs {
 
84
namespace android {
 
85
 
 
86
class MediaSourceBuffer : public video::Buffer
 
87
{
 
88
public:
 
89
    typedef std::shared_ptr<MediaSourceBuffer> Ptr;
 
90
 
 
91
    ~MediaSourceBuffer() {
 
92
        if (!buffer_)
 
93
            return;
 
94
 
 
95
        const auto ref_count = media_buffer_get_refcount(buffer_);
 
96
 
 
97
        // If someone has set a reference on the buffer we just have to
 
98
        // release it here and the other one will take care about actually
 
99
        // destroying it.
 
100
        if (ref_count > 0)
 
101
            media_buffer_release(buffer_);
 
102
        else
 
103
            media_buffer_destroy(buffer_);
 
104
 
 
105
    }
 
106
 
 
107
    static MediaSourceBuffer::Ptr Create(MediaBufferWrapper *buffer) {
 
108
        const auto sp = std::shared_ptr<MediaSourceBuffer>(new MediaSourceBuffer);
 
109
        sp->buffer_ = buffer;
 
110
        sp->ExtractTimestamp();
 
111
        return sp;
 
112
    }
 
113
 
 
114
    virtual uint32_t Length() const {
 
115
        return media_buffer_get_size(buffer_);
 
116
    }
 
117
 
 
118
    virtual uint8_t* Data() {
 
119
        return static_cast<uint8_t*>(media_buffer_get_data(buffer_));
 
120
    }
 
121
 
 
122
    virtual bool IsValid() const {
 
123
        return buffer_ != nullptr;
 
124
    }
 
125
 
 
126
private:
 
127
    void ExtractTimestamp() {
 
128
        const auto meta_data = media_buffer_get_meta_data(buffer_);
 
129
        if (!meta_data)
 
130
            return;
 
131
 
 
132
        const uint32_t key_time = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_TIME);
 
133
        int64_t time_us = 0;
 
134
        media_meta_data_find_int64(meta_data, key_time, &time_us);
 
135
 
 
136
        SetTimestamp(time_us);
 
137
    }
 
138
 
 
139
private:
 
140
    MediaBufferWrapper *buffer_;
 
141
};
 
142
 
 
143
video::BaseEncoder::Config H264Encoder::DefaultConfiguration() {
 
144
    Config config;
 
145
    config.framerate = kAnyFramerate;
 
146
    config.bitrate = kDefaultBitrate;
 
147
    config.i_frame_interval = kDefaultIFrameInterval.count();
 
148
    config.intra_refresh_mode = kOMXVideoIntraRefreshCyclic;
 
149
    return config;
 
150
}
 
151
 
 
152
video::BaseEncoder::Ptr H264Encoder::Create() {
 
153
    return std::shared_ptr<H264Encoder>(new H264Encoder);
 
154
}
 
155
 
 
156
H264Encoder::H264Encoder() :
 
157
    format_(nullptr),
 
158
    source_(nullptr),
 
159
    source_format_(nullptr),
 
160
    encoder_(nullptr),
 
161
    running_(false),
 
162
    input_queue_(mcs::video::BufferQueue::Create()),
 
163
    start_time_(-1ll),
 
164
    frame_count_(0) {
 
165
}
 
166
 
 
167
H264Encoder::~H264Encoder() {
 
168
    Stop();
 
169
 
 
170
    if (encoder_)
 
171
        media_codec_source_release(encoder_);
 
172
 
 
173
    if (source_)
 
174
        media_source_release(source_);
 
175
 
 
176
    if (format_)
 
177
        media_message_release(format_);
 
178
 
 
179
    if (source_format_)
 
180
        media_meta_data_release(source_format_);
 
181
}
 
182
 
 
183
bool H264Encoder::Configure(const Config &config) {
 
184
    if (encoder_)
 
185
        return false;
 
186
 
 
187
    MCS_DEBUG("configuring with %dx%d@%d", config.width, config.height, config.framerate);
 
188
 
 
189
    auto format = media_message_create();
 
190
    if (!format)
 
191
        return false;
 
192
 
 
193
    media_message_set_string(format, kFormatKeyMime, kH264MimeType, 0);
 
194
 
 
195
    media_message_set_int32(format, kFormatKeyStoreMetaDataInBuffers, true);
 
196
    media_message_set_int32(format, kFormatKeyStoreMetaDataInBuffersOutput, false);
 
197
 
 
198
    media_message_set_int32(format, kFormatKeyWidth, config.width);
 
199
    media_message_set_int32(format, kFormatKeyHeight, config.height);
 
200
    media_message_set_int32(format, kFormatKeyStride, config.width);
 
201
    media_message_set_int32(format, kFormatKeySliceHeight, config.width);
 
202
 
 
203
    media_message_set_int32(format, kFormatKeyColorFormat, kOMXColorFormatAndroidOpaque);
 
204
 
 
205
    media_message_set_int32(format, kFormatKeyBitrate, config.bitrate);
 
206
    media_message_set_int32(format, kFormatKeyBitrateMode, kOMXVideoControlRateConstant);
 
207
    media_message_set_int32(format, kFormatKeyFramerate, config.framerate);
 
208
 
 
209
    media_message_set_int32(format, kFormatKeyIntraRefreshMode, 0);
 
210
 
 
211
    // Update macroblocks in a cyclic fashion with 10% of all MBs within
 
212
    // frame gets updated at one time. It takes about 10 frames to
 
213
    // completely update a whole video frame. If the frame rate is 30,
 
214
    // it takes about 333 ms in the best case (if next frame is not an IDR)
 
215
    // to recover from a lost/corrupted packet.
 
216
    const int32_t mbs = (((config.width + 15) / 16) * ((config.height + 15) / 16) * 10) / 100;
 
217
    media_message_set_int32(format, kFormatKeyIntraRefreshCIRMbs, mbs);
 
218
 
 
219
    if (config.i_frame_interval > 0)
 
220
        media_message_set_int32(format, kFormatKeyIFrameInterval, config.i_frame_interval);
 
221
 
 
222
    if (config.profile_idc > 0)
 
223
        media_message_set_int32(format, kFormatKeyProfileIdc, config.profile_idc);
 
224
 
 
225
    if (config.level_idc > 0)
 
226
        media_message_set_int32(format, kFormatKeyLevelIdc, config.level_idc);
 
227
 
 
228
    if (config.constraint_set > 0)
 
229
        media_message_set_int32(format, kFormatKeyConstraintSet, config.constraint_set);
 
230
 
 
231
    // FIXME we need to find a way to check if the encoder supports prepending
 
232
    // SPS/PPS to the buffers it is producing or if we have to manually do that
 
233
    media_message_set_int32(format, kFormatKeyPrependSpsPpstoIdrFrames, 1);
 
234
 
 
235
    source_ = media_source_create();
 
236
    if (!source_) {
 
237
        MCS_ERROR("Failed to create media input source for encoder");
 
238
        media_message_release(format);
 
239
        return false;
 
240
    }
 
241
 
 
242
    auto source_format = media_meta_data_create();
 
243
    if (!source_format) {
 
244
        MCS_ERROR("Failed to create media meta data for encoder source");
 
245
        media_message_release(format);
 
246
        media_source_release(source_);
 
247
        source_ = nullptr;
 
248
        return false;
 
249
    }
 
250
 
 
251
    // Notice that we're passing video/raw as mime type here which is quite
 
252
    // important to let the encoder do the right thing with the incoming data
 
253
    media_meta_data_set_cstring(source_format,
 
254
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_MIME),
 
255
        kRawMimeType);
 
256
 
 
257
    // We're setting the opaque color format here as the encoder is then
 
258
    // meant to figure out the color format from the GL frames itself.
 
259
    media_meta_data_set_int32(source_format,
 
260
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_COLOR_FORMAT),
 
261
        kOMXColorFormatAndroidOpaque);
 
262
 
 
263
    media_meta_data_set_int32(source_format,
 
264
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_WIDTH),
 
265
        config.width);
 
266
    media_meta_data_set_int32(source_format,
 
267
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_HEIGHT),
 
268
        config.height);
 
269
    media_meta_data_set_int32(source_format,
 
270
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_STRIDE),
 
271
        config.width);
 
272
    media_meta_data_set_int32(source_format,
 
273
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_SLICE_HEIGHT),
 
274
        config.height);
 
275
    media_meta_data_set_int32(source_format,
 
276
        media_meta_data_get_key_id(MEDIA_META_DATA_KEY_FRAMERATE),
 
277
        config.framerate);
 
278
 
 
279
    media_source_set_format(source_, source_format);
 
280
 
 
281
    media_source_set_start_callback(source_, &H264Encoder::OnSourceStart, this);
 
282
    media_source_set_stop_callback(source_, &H264Encoder::OnSourceStop, this);
 
283
    media_source_set_read_callback(source_, &H264Encoder::OnSourceRead, this);
 
284
    media_source_set_pause_callback(source_, &H264Encoder::OnSourcePause, this);
 
285
 
 
286
    encoder_ = media_codec_source_create(format, source_, 0);
 
287
    if (!encoder_) {
 
288
        MCS_ERROR("Failed to create encoder instance");
 
289
        media_meta_data_release(source_format);
 
290
        media_message_release(format);
 
291
        media_source_release(source_);
 
292
        source_ = nullptr;
 
293
        return false;
 
294
    }
 
295
 
 
296
    config_ = config;
 
297
    format_ = format;
 
298
    source_format_ = source_format;
 
299
 
 
300
    MCS_DEBUG("Configured encoder succesfully");
 
301
 
 
302
    return true;
 
303
}
 
304
 
 
305
bool H264Encoder::Start() {
 
306
    if (!encoder_ || running_)
 
307
        return false;
 
308
 
 
309
    // We have to set us to running before we start the media
 
310
    // codec source as that will directly call OnSourceRead
 
311
    // which will fail if running_ isn't set to true.
 
312
    running_ = true;
 
313
 
 
314
    if (!media_codec_source_start(encoder_)) {
 
315
        MCS_ERROR("Failed to start encoder");
 
316
        running_ = false;
 
317
        return false;
 
318
    }
 
319
 
 
320
    MCS_DEBUG("Started encoder");
 
321
 
 
322
    return true;
 
323
}
 
324
 
 
325
int H264Encoder::OnSourceStart(MediaMetaDataWrapper *meta, void *user_data) {
 
326
    boost::ignore_unused_variable_warning(meta);
 
327
    boost::ignore_unused_variable_warning(user_data);
 
328
 
 
329
    MCS_DEBUG("");
 
330
 
 
331
    return 0;
 
332
}
 
333
 
 
334
int H264Encoder::OnSourceStop(void *user_data) {
 
335
    boost::ignore_unused_variable_warning(user_data);
 
336
 
 
337
    MCS_DEBUG("");
 
338
 
 
339
    return 0;
 
340
}
 
341
 
 
342
int H264Encoder::OnSourcePause(void *user_data) {
 
343
    boost::ignore_unused_variable_warning(user_data);
 
344
 
 
345
    MCS_DEBUG("");
 
346
 
 
347
    return 0;
 
348
}
 
349
 
 
350
MediaBufferWrapper* H264Encoder::PackBuffer(const mcs::video::Buffer::Ptr &input_buffer, const mcs::TimestampUs timestamp) {
 
351
    if (!input_buffer->NativeHandle()) {
 
352
        MCS_WARNING("Ignoring buffer without native handle");
 
353
        return nullptr;
 
354
    }
 
355
 
 
356
    const auto anwb = reinterpret_cast<ANativeWindowBuffer*>(input_buffer->NativeHandle());
 
357
 
 
358
    uint32_t type = kMetadataBufferTypeGrallocSource;
 
359
    const size_t size = sizeof(buffer_handle_t) + sizeof(type);
 
360
 
 
361
    // We let the media buffer allocate the memory here to let it keep
 
362
    // the ownership and release the memory once its destroyed.
 
363
    auto buffer = media_buffer_create(size);
 
364
    if (!buffer)
 
365
        return nullptr;
 
366
 
 
367
    auto data = media_buffer_get_data(buffer);
 
368
 
 
369
    // We're passing the buffer handle directly as part of the buffer data
 
370
    // here to the encoder and it will figure out it has to deal with a
 
371
    // buffer with the key value we put in front of it. See also
 
372
    // frameworks/av/media/libstagefright/SurfaceMediaSource.cpp for more
 
373
    // details about this.
 
374
    memcpy(data, &type, sizeof(type));
 
375
    memcpy(data + sizeof(type), &anwb->handle, sizeof(buffer_handle_t));
 
376
 
 
377
    media_buffer_set_return_callback(buffer, &H264Encoder::OnBufferReturned, this);
 
378
 
 
379
    // We need to put a reference on the buffer here if we want the
 
380
    // callback we set above being called.
 
381
    media_buffer_ref(buffer);
 
382
 
 
383
    auto meta = media_buffer_get_meta_data(buffer);
 
384
    const auto key_time = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_TIME);
 
385
    media_meta_data_set_int64(meta, key_time, timestamp);
 
386
 
 
387
    pending_buffers_.push_back(BufferItem{input_buffer, buffer});
 
388
 
 
389
    return buffer;
 
390
}
 
391
 
 
392
int H264Encoder::OnSourceRead(MediaBufferWrapper **buffer, void *user_data) {
 
393
    auto thiz = static_cast<H264Encoder*>(user_data);
 
394
 
 
395
    if (!thiz || !thiz->running_)
 
396
        return kAndroidMediaErrorNotConnected;
 
397
 
 
398
    if (!buffer)
 
399
        return kAndroidMediaErrorBufferTooSmall;
 
400
 
 
401
    const auto input_buffer = thiz->input_queue_->Next();
 
402
 
 
403
    const auto next_buffer = thiz->PackBuffer(input_buffer, input_buffer->Timestamp());
 
404
 
 
405
    if (!next_buffer)
 
406
        return kAndroidMediaErrorEndOfStream;
 
407
 
 
408
    *buffer = next_buffer;
 
409
 
 
410
    return 0;
 
411
}
 
412
 
 
413
void H264Encoder::OnBufferReturned(MediaBufferWrapper *buffer, void *user_data) {
 
414
    auto thiz = static_cast<H264Encoder*>(user_data);
 
415
 
 
416
    if (!thiz)
 
417
        return;
 
418
 
 
419
    // Find the right pending buffer matching the returned one
 
420
    auto iter = thiz->pending_buffers_.begin();
 
421
    for (; iter != thiz->pending_buffers_.end(); ++iter) {
 
422
        if (iter->media_buffer == buffer)
 
423
            break;
 
424
    }
 
425
 
 
426
    if (iter == thiz->pending_buffers_.end()) {
 
427
        MCS_WARNING("Didn't remember returned buffer!?");
 
428
        return;
 
429
    }
 
430
 
 
431
    // Unset observer to be able to call release on the MediaBuffer
 
432
    // and reduce its reference count. It has an internal check if
 
433
    // an observer is still set or not before it will actually release
 
434
    // itself.
 
435
    media_buffer_set_return_callback(iter->media_buffer, nullptr, nullptr);
 
436
    media_buffer_release(iter->media_buffer);
 
437
 
 
438
    auto buf = iter->buffer;
 
439
    thiz->pending_buffers_.erase(iter);
 
440
 
 
441
    // After we've cleaned up everything we can send the buffer
 
442
    // back to the producer which then can reuse it.
 
443
    buf->Release();
 
444
}
 
445
 
 
446
bool H264Encoder::DoesBufferContainCodecConfig(MediaBufferWrapper *buffer) {
 
447
    auto meta_data = media_buffer_get_meta_data(buffer);
 
448
    if (!meta_data)
 
449
        return false;
 
450
 
 
451
    uint32_t key_is_codec_config = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_IS_CODEC_CONFIG);
 
452
    int32_t is_codec_config = 0;
 
453
    media_meta_data_find_int32(meta_data, key_is_codec_config, &is_codec_config);
 
454
    return static_cast<bool>(is_codec_config);
 
455
}
 
456
 
 
457
bool H264Encoder::Execute() {
 
458
    if (!running_) {
 
459
        MCS_ERROR("Tried to execute encoder while not started");
 
460
        return false;
 
461
    }
 
462
 
 
463
    MediaBufferWrapper *buffer = nullptr;
 
464
    if (!media_codec_source_read(encoder_, &buffer)) {
 
465
        MCS_ERROR("Failed to read a new buffer from encoder");
 
466
        return false;
 
467
    }
 
468
 
 
469
    auto mbuf = MediaSourceBuffer::Create(buffer);
 
470
 
 
471
    if (mbuf->Timestamp() > 0) {
 
472
        const int64_t now = mcs::Utils::GetNowUs();
 
473
        const int64_t diff = (now - mbuf->Timestamp()) / 1000ll;
 
474
        video::Statistics::Instance()->RecordEncoderBufferOut(diff);
 
475
    }
 
476
 
 
477
    if (DoesBufferContainCodecConfig(buffer)) {
 
478
        if (auto sp = delegate_.lock())
 
479
            sp->OnBufferWithCodecConfig(mbuf);
 
480
    }
 
481
 
 
482
    if (auto sp = delegate_.lock())
 
483
        sp->OnBufferAvailable(mbuf);
 
484
 
 
485
    return true;
 
486
}
 
487
 
 
488
bool H264Encoder::Stop() {
 
489
    if (!encoder_ || !running_)
 
490
        return false;
 
491
 
 
492
    if (!media_codec_source_stop(encoder_))
 
493
        return false;
 
494
 
 
495
    running_ = false;
 
496
 
 
497
    return true;
 
498
}
 
499
 
 
500
void H264Encoder::QueueBuffer(const video::Buffer::Ptr &buffer) {
 
501
    if (!running_)
 
502
        return;
 
503
 
 
504
    input_queue_->Push(buffer);
 
505
}
 
506
 
 
507
void* H264Encoder::NativeWindowHandle() const {
 
508
    if (!encoder_)
 
509
        return nullptr;
 
510
 
 
511
    return media_codec_source_get_native_window_handle(encoder_);
 
512
}
 
513
 
 
514
video::BaseEncoder::Config H264Encoder::Configuration() const {
 
515
    return config_;
 
516
}
 
517
 
 
518
void H264Encoder::SendIDRFrame() {
 
519
    if (!encoder_)
 
520
        return;
 
521
 
 
522
    MCS_DEBUG("");
 
523
 
 
524
    media_codec_source_request_idr_frame(encoder_);
 
525
}
 
526
 
 
527
} // namespace android
 
528
} // namespace mcs