Merge lp:~morphis/aethercast/hw-encoding-support into lp:aethercast

Proposed by Simon Fels
Status: Superseded
Proposed branch: lp:~morphis/aethercast/hw-encoding-support
Merge into: lp:aethercast
Prerequisite: lp:~morphis/aethercast/use-wpa-dbus
Diff against target: 20315 lines (+8563/-6702)
191 files modified
.gitignore (+1/-0)
CMakeLists.txt (+14/-1)
cmake/LinuxCrossCompile.cmake (+43/-0)
conf/dhcpd.conf (+0/-5)
cross-compile-chroot.sh (+163/-0)
data/fi.w1.wpa_supplicant1.xml (+0/-109)
data/org.aethercast.xml (+2/-0)
debian/aethercast-tools.install (+1/-0)
debian/aethercast.install (+0/-1)
debian/control (+26/-3)
debian/rules (+4/-0)
debian/usr.sbin.aethercast (+13/-9)
scripts/setup-partial-armhf-chroot.sh (+155/-0)
src/CMakeLists.txt (+63/-18)
src/mcs/android/h264encoder.cpp (+464/-0)
src/mcs/android/h264encoder.h (+96/-0)
src/mcs/basesourcemediamanager.cpp (+59/-26)
src/mcs/basesourcemediamanager.h (+8/-3)
src/mcs/config.h.in (+0/-25)
src/mcs/forwardingmiracastcontroller.cpp (+6/-2)
src/mcs/forwardingmiracastcontroller.h (+3/-1)
src/mcs/forwardingnetworkdevice.cpp (+0/-51)
src/mcs/forwardingnetworkdevice.h (+0/-42)
src/mcs/gstsourcemediamanager.cpp (+19/-2)
src/mcs/gstsourcemediamanager.h (+2/-2)
src/mcs/initgstreameronce.cpp (+88/-0)
src/mcs/initgstreameronce.h (+29/-0)
src/mcs/logger.cpp (+20/-2)
src/mcs/logger.h (+3/-0)
src/mcs/mediamanagerfactory.cpp (+8/-4)
src/mcs/mediamanagerfactory.h (+1/-1)
src/mcs/mir/mediasender.cpp (+155/-0)
src/mcs/mir/mediasender.h (+75/-0)
src/mcs/mir/sourcemediamanager.cpp (+130/-93)
src/mcs/mir/sourcemediamanager.h (+50/-8)
src/mcs/mir/streamconnector.cpp (+204/-0)
src/mcs/mir/streamconnector.h (+77/-0)
src/mcs/mir/streamrenderer.cpp (+175/-0)
src/mcs/mir/streamrenderer.h (+69/-0)
src/mcs/miracastcontroller.h (+3/-1)
src/mcs/miracastcontrollerskeleton.cpp (+35/-1)
src/mcs/miracastcontrollerskeleton.h (+2/-0)
src/mcs/miracastservice.cpp (+34/-8)
src/mcs/miracastservice.h (+5/-1)
src/mcs/miracastsourceclient.cpp (+15/-6)
src/mcs/miracastsourceclient.h (+7/-5)
src/mcs/miracastsourcemanager.cpp (+6/-5)
src/mcs/miracastsourcemanager.h (+3/-2)
src/mcs/networkdeviceskeleton.cpp (+0/-142)
src/mcs/networkutils.cpp (+61/-3)
src/mcs/networkutils.h (+3/-0)
src/mcs/streaming/mpegtspacketizer.cpp (+831/-0)
src/mcs/streaming/mpegtspacketizer.h (+97/-0)
src/mcs/streaming/rtpsender.cpp (+308/-0)
src/mcs/streaming/rtpsender.h (+69/-0)
src/mcs/systemcontroller.cpp (+31/-0)
src/mcs/systemcontroller.h (+79/-0)
src/mcs/testsourcemediamanager.cpp (+29/-4)
src/mcs/types.h (+3/-0)
src/mcs/ubuntu/powerd.cpp (+27/-0)
src/mcs/ubuntu/powerd.h (+31/-0)
src/mcs/ubuntu/powerdsystemlock.cpp (+93/-0)
src/mcs/ubuntu/powerdsystemlock.h (+56/-0)
src/mcs/ubuntu/systemcontroller.cpp (+42/-0)
src/mcs/ubuntu/systemcontroller.h (+42/-0)
src/mcs/ubuntu/unity.cpp (+28/-0)
src/mcs/ubuntu/unity.h (+33/-0)
src/mcs/ubuntu/unitydisplaylock.cpp (+128/-0)
src/mcs/ubuntu/unitydisplaylock.h (+56/-0)
src/mcs/utils.cpp (+57/-2)
src/mcs/utils.h (+19/-1)
src/mcs/video/baseencoder.cpp (+33/-0)
src/mcs/video/baseencoder.h (+112/-0)
src/mcs/video/buffer.cpp (+99/-0)
src/mcs/video/buffer.h (+83/-0)
src/mcs/video/bufferqueue.cpp (+131/-0)
src/mcs/video/bufferqueue.h (+76/-0)
src/mcs/video/h264analyzer.cpp (+115/-0)
src/mcs/video/h264analyzer.h (+60/-0)
src/mcs/video/statistics.cpp (+134/-0)
src/mcs/video/statistics.h (+74/-0)
src/mcs/video/utils.cpp (+39/-0)
src/mcs/video/utils.h (+33/-0)
src/mcs/video/utils_from_android.cpp (+112/-0)
src/mcs/video/videoformat.cpp (+416/-0)
src/mcs/video/videoformat.h (+46/-0)
src/mcs/x11sourcemediamanager.cpp (+0/-51)
src/mcs/x11sourcemediamanager.h (+0/-38)
src/mcs/x264.cpp (+206/-0)
src/mcs/x264.h (+82/-0)
src/w11tng/config.h.in (+0/-27)
src/w11tng/dhcpclient.cpp (+2/-0)
src/w11tng/dhcpleaseparser.cpp (+0/-130)
src/w11tng/dhcpleaseparser.h (+0/-51)
src/w11tng/dhcpserver.cpp (+5/-5)
src/w11tng/filemonitor.cpp (+0/-74)
src/w11tng/filemonitor.h (+0/-60)
src/w11tng/hostname1stub.cpp (+0/-136)
src/w11tng/hostname1stub.h (+0/-73)
src/w11tng/informationelement.cpp (+0/-171)
src/w11tng/informationelement.h (+0/-165)
src/w11tng/interfaceselector.cpp (+0/-125)
src/w11tng/interfaceselector.h (+0/-66)
src/w11tng/interfacestub.cpp (+0/-95)
src/w11tng/interfacestub.h (+0/-69)
src/w11tng/managerstub.cpp (+0/-202)
src/w11tng/managerstub.h (+0/-83)
src/w11tng/netlinklistener.cpp (+0/-205)
src/w11tng/netlinklistener.h (+0/-64)
src/w11tng/networkdevice.cpp (+0/-126)
src/w11tng/networkdevice.h (+0/-92)
src/w11tng/networkmanager.cpp (+56/-8)
src/w11tng/networkmanager.h (+19/-4)
src/w11tng/p2pdevicestub.cpp (+0/-447)
src/w11tng/p2pdevicestub.h (+0/-112)
src/w11tng/peerstub.cpp (+0/-165)
src/w11tng/peerstub.h (+0/-77)
src/w11tng/processexecutor.cpp (+0/-102)
src/w11tng/processexecutor.h (+0/-56)
src/w11tng/wififirmwareloader.cpp (+0/-94)
src/w11tng/wififirmwareloader.h (+0/-55)
tests/3rd_party/lxc-nl/CMakeLists.txt (+0/-6)
tests/3rd_party/lxc-nl/network.c (+0/-308)
tests/3rd_party/lxc-nl/network.h (+0/-34)
tests/3rd_party/lxc-nl/nl.c (+0/-313)
tests/3rd_party/lxc-nl/nl.h (+0/-260)
tests/CMakeLists.txt (+2/-0)
tests/common/dbusfixture.cpp (+0/-190)
tests/common/dbusfixture.h (+0/-67)
tests/common/dbusnameowner.cpp (+0/-43)
tests/common/dbusnameowner.h (+0/-44)
tests/common/glibhelpers.cpp (+0/-43)
tests/common/glibhelpers.h (+0/-34)
tests/common/virtualnetwork.cpp (+0/-56)
tests/common/virtualnetwork.h (+0/-42)
tests/mcs/CMakeLists.txt (+3/-0)
tests/mcs/forwardingmiracastcontroller_tests.cpp (+5/-2)
tests/mcs/forwardingnetworkdevice_tests.cpp (+0/-50)
tests/mcs/mediamanagerfactory_tests.cpp (+3/-3)
tests/mcs/miracastcontrollerskeleton_tests.cpp (+5/-2)
tests/mcs/mock_network_device.h (+0/-35)
tests/mcs/networkdevice_tests.cpp (+0/-36)
tests/mcs/networkdeviceskeleton_tests.cpp (+0/-51)
tests/mcs/networkmanagerfactory_tests.cpp (+0/-44)
tests/mcs/streaming/CMakeLists.txt (+1/-0)
tests/mcs/streaming/mpegtspacketizer_tests.cpp (+44/-0)
tests/mcs/video/CMakeLists.txt (+1/-0)
tests/mcs/video/h264analyzer_tests.cpp (+87/-0)
tests/mcs/x264_tests.cpp (+86/-0)
tests/w11tng.moved/CMakeLists.txt (+14/-0)
tests/w11tng.moved/baseskeleton.cpp (+58/-0)
tests/w11tng.moved/baseskeleton.h (+49/-0)
tests/w11tng.moved/dhcp_tests.cpp (+66/-0)
tests/w11tng.moved/dhcpleaseparser_tests.cpp (+93/-0)
tests/w11tng.moved/informationelement_tests.cpp (+62/-0)
tests/w11tng.moved/interfaceselector_tests.cpp (+158/-0)
tests/w11tng.moved/interfaceskeleton.cpp (+43/-0)
tests/w11tng.moved/interfaceskeleton.h (+45/-0)
tests/w11tng.moved/interfacestub_tests.cpp (+75/-0)
tests/w11tng.moved/netlinklistener_tests.cpp (+67/-0)
tests/w11tng.moved/p2pdeviceskeleton.cpp (+137/-0)
tests/w11tng.moved/p2pdeviceskeleton.h (+72/-0)
tests/w11tng.moved/p2pdevicestub_tests.cpp (+192/-0)
tests/w11tng.moved/peerskeleton.cpp (+40/-0)
tests/w11tng.moved/peerskeleton.h (+44/-0)
tests/w11tng.moved/peerstub_tests.cpp (+73/-0)
tests/w11tng/CMakeLists.txt (+0/-14)
tests/w11tng/baseskeleton.cpp (+0/-58)
tests/w11tng/baseskeleton.h (+0/-49)
tests/w11tng/dhcpleaseparser_tests.cpp (+0/-93)
tests/w11tng/informationelement_tests.cpp (+0/-62)
tests/w11tng/interfaceselector_tests.cpp (+0/-158)
tests/w11tng/interfaceskeleton.cpp (+0/-43)
tests/w11tng/interfaceskeleton.h (+0/-45)
tests/w11tng/interfacestub_tests.cpp (+0/-75)
tests/w11tng/netlinklistener_tests.cpp (+0/-67)
tests/w11tng/p2pdeviceskeleton.cpp (+0/-137)
tests/w11tng/p2pdeviceskeleton.h (+0/-72)
tests/w11tng/p2pdevicestub_tests.cpp (+0/-192)
tests/w11tng/peerskeleton.cpp (+0/-40)
tests/w11tng/peerskeleton.h (+0/-44)
tests/w11tng/peerstub_tests.cpp (+0/-73)
tests/wds/CMakeLists.txt (+1/-0)
tests/wds/videoformatselection_tests.cpp (+72/-0)
tools/CMakeLists.txt (+65/-0)
tools/mirscreencast_to_android_hw_enc.cpp (+64/-0)
tools/mirscreencast_to_stream.cpp (+124/-0)
tools/mpegts_muxer.cpp (+100/-0)
tools/raw_streamer.cpp (+95/-0)
tools/simplesource.cpp (+73/-0)
tools/simplesource.h (+52/-0)
To merge this branch: bzr merge lp:~morphis/aethercast/hw-encoding-support
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+284113@code.launchpad.net

This proposal supersedes a proposal from 2016-01-27.

Commit message

Add HW encoding support

Description of the change

Add HW encoding support

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:136
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/60/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/59/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/60/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/59/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/60/rebuild

review: Needs Fixing (continuous-integration)
137. By Simon Fels

Abstract mir stream connection behind a connector

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:137
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/61/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/60/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/61/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/60/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/61/rebuild

review: Needs Fixing (continuous-integration)
138. By Simon Fels

Add stream renderer which gets frames from mir and sends them to the encoder

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:138
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/62/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/61/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/62/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/61/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/62/rebuild

review: Needs Fixing (continuous-integration)
139. By Simon Fels

Integrate stream renderer with miracast source manager

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:139
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/63/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/62/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/63/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/62/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/63/rebuild

review: Needs Fixing (continuous-integration)
140. By Simon Fels

Make d'tor of base class correctly virtual

141. By Simon Fels

Force mir as default media manager

142. By Simon Fels

Add missing return type for function

143. By Simon Fels

Extended debugging output for mir source manager

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:143
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/64/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/63/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/64/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/63/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/64/rebuild

review: Needs Fixing (continuous-integration)
144. By Simon Fels

All changes to get streaming working

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:144
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/65/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/64/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/65/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/64/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/65/rebuild

review: Needs Fixing (continuous-integration)
145. By Simon Fels

Add support to retrieve raw output from the encoder

146. By Simon Fels

Actually stop the stream renderer on destruction

147. By Simon Fels

Set H264 profile/level/constraint for encoder

148. By Simon Fels

Make sure the encoder os properly initialized before starting

149. By Simon Fels

Take raw h264 frames from encoder as input for the pipeline

150. By Simon Fels

Check for possible errors on encoder construction

151. By Simon Fels

Don't call not existing libmedia API method for now

152. By Simon Fels

Construct pipeline with parse/mux/pay elements

153. By Simon Fels

Limit what resolutions, fps, codec parameters we can provide

154. By Simon Fels

Raise our GO intent to always become the group owner

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:154
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/67/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/66/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/67/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/66/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/67/rebuild

review: Needs Fixing (continuous-integration)
155. By Simon Fels

Drop superflous pipeline state change

156. By Simon Fels

Dump the actual framerate we're recording with from mir

157. By Simon Fels

Drop h264parse element and just use caps

158. By Simon Fels

Simply mirscreencast utility to just dump to a file

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:158
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/68/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/67/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/68/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/67/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/68/rebuild

review: Needs Fixing (continuous-integration)
159. By Simon Fels

Add queue elements for extended buffering

160. By Simon Fels

Add proper .gitignore file

161. By Simon Fels

Take buffers from android and put them into Gstreamer ones

162. By Simon Fels

Add utility to use plain streaming for testing

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:162
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/69/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/68/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/69/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/68/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/69/rebuild

review: Needs Fixing (continuous-integration)
163. By Simon Fels

tools: stream: start source on startup

164. By Simon Fels

tools: screencast: initialize gstreamer on startup

165. By Simon Fels

tools: stream: run forever and react on SIGINT/SIGTERM

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:165
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/70/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/69/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/70/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/69/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/70/rebuild

review: Needs Fixing (continuous-integration)
166. By Simon Fels

Include current thread id in each log message

167. By Simon Fels

Only submit buffers to the pipeline when its ready for new ones

If we're producing buffers at a too hight rate we're getting them with
incorrect timestamps into the pipeline which leads to delays on the
receiver side because PCR/PTS of the MPEGTS stream doesn't match anymore.

This will be further optimized.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:167
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/71/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/70/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/71/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/70/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/71/rebuild

review: Needs Fixing (continuous-integration)
168. By Simon Fels

Ignore unused function parameters

169. By Simon Fels

Drop superflous debug statements

170. By Simon Fels

Add dirty option to dump the stream rather than sending it out

171. By Simon Fels

Link source and mux together with a pad to specify the MPEGTS PID

The WiFi Display spec requires us to send the video stream on a
specific PID (0x1011) which we can request to the mpegtsmux
element by request a pad with a specific name.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:171
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/hw-encoding-support/+merge/284113/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/72/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/71/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/72/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/71/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/72/rebuild

review: Needs Fixing (continuous-integration)
172. By Simon Fels

mir: simply pad request/link for mpegtsmux element

173. By Simon Fels

Drop changed PMT/PAT intervals

174. By Simon Fels

Comment on how we're requesting a different stream PID

175. By Simon Fels

Switch to nal alignment

176. By Simon Fels

Merge branch 'trunk' into hw-encoding-support

177. By Simon Fels

Merge trunk

178. By Simon Fels

Add missing files lost due to a failed merge with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
179. By Simon Fels

Request 188 byte length packages from MPEGTS element

180. By Simon Fels

debian: add missing build depends

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
181. By Simon Fels

debian: add missing libgstreamer-plugins-base1.0-dev dependency

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
182. By Simon Fels

Fail when pipeline can't be configured

183. By Simon Fels

Add support for an extended display

184. By Simon Fels

Correct vertex position data to use the full screen

185. By Simon Fels

Draw white background so we're able to discover empty fragments

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
186. By Simon Fels

Add base encoder class and start a H264EncoderNext implementation

187. By Simon Fels

Print out timestamps for performance analysis

188. By Simon Fels

Refactor encoder integration and finalize new H264 implementation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
189. By Simon Fels

Make new h264 encoder working properly

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
190. By Simon Fels

Tune default encoder values to follow what Android does for WFD

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
191. By Simon Fels

Implement MPEGTS packetizer

Based on the implementation from Android.

192. By Simon Fels

Optimizer buffer timestamps and encoder configuration

193. By Simon Fels

Adding missing encoder config field

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
194. By Simon Fels

A lot more work on getting rid of gstreamer

Adding own RTP sender implementation which is now properly used
from a new source media manager type called 'mir-next'.

This also refactors some parts of the already existing code.

195. By Simon Fels

Drop accidentially added code

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
196. By Simon Fels

Enable dumping of the MPEGTS stream

197. By Simon Fels

Extract codec specific data and prepend to AVC buffers

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
198. By Simon Fels

Be less verbose for encoder output

199. By Simon Fels

Tell MPEGTS packetizer to include SPS/PPS with IDR frames

200. By Simon Fels

Add utility method to create a hexdump

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
201. By Simon Fels

Take SPS/PPS from codec data when available

202. By Simon Fels

Add H264 analyzer to collect statistics

203. By Simon Fels

Don't tell the MPEGST packtizer to add SPS/PPS to IDR frames

204. By Simon Fels

Let encoder submit buffer with codec-specific data for transmission

205. By Simon Fels

Add output to measure performance

206. By Simon Fels

Pass local address down to our WDS delegate

We need to transmit our local address correctly within the RTSP
message we're exchanging with the other side which we missed
until now.

207. By Simon Fels

Extract timestamp from buffer we get from the encoder

208. By Simon Fels

Use proper constants for encoder configuration

209. By Simon Fels

Increase video bitrate to have a stable picture

210. By Simon Fels

Check for valid meta data structure before accessing it

211. By Simon Fels

Don't set buffer timestamp manually

212. By Simon Fels

Let encoder include SPS/PPS with each IDR frame

213. By Simon Fels

Ask encoder to store meta data in buffers

214. By Simon Fels

Adjust for WDS 1.0.0 API changes

215. By Simon Fels

MPEGTS packetizer fixes

216. By Simon Fels

Raise our process priority

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
217. By Simon Fels

Revert try to move buffer timestamp ahead

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
218. By Simon Fels

Add a proper buffer queue for Media/RTP sender

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
219. By Simon Fels

Add a measure point abstraction class

220. By Simon Fels

Decouple texture creation and rendering

221. By Simon Fels

Add missing macro

222. By Simon Fels

But add the macro at the right place

223. By Simon Fels

Work with a not-blocking socket

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
224. By Simon Fels

Revert buffer queue for stream renderer

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
225. By Simon Fels

Force GO intent to 15 for now

226. By Simon Fels

Cleanup old H264Encoder instance

227. By Simon Fels

tools: let utility build again even if not functional now

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
228. By Simon Fels

android: first bits of the h264 encoder implementation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
229. By Simon Fels

Implement new encoder which directly forwards native buffers from mir

230. By Simon Fels

Unblock input buffer queue when taking a buffer out

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
231. By Simon Fels

tools: mpegts_muxer: specifiy file open mode properly

232. By Simon Fels

tools: mirscreencast_to_stream: add cmdline option to extend the display

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
233. By Simon Fels

Pass dimensions correct to the screencast instance

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
234. By Simon Fels

Drop unneeded log message

235. By Simon Fels

Some further explaining comments

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
236. By Simon Fels

Fix syntax error in build configuration

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
237. By Simon Fels

Disable gstreamer initialization for now

238. By Simon Fels

Do an async swap buffers call to mir for direct rendering

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
239. By Simon Fels

Correct debug statement order

240. By Simon Fels

Optimize some more debug statements

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
241. By Simon Fels

Optimize buffer timestamp logging

We're only interested in how late we're with a buffer and nothing
else as that is what is causing our delay.

242. By Simon Fels

Timestamp buffer directly after we received them

243. By Simon Fels

Further timestamp logging optimizations

244. By Simon Fels

Drop unneeded buffer refcount logging

245. By Simon Fels

Further timestamp logging adjustments

246. By Simon Fels

Drop two more unneeded debug log statements

247. By Simon Fels

Include now in timestamp logging

248. By Simon Fels

For stick to synchronously processing a single buffer

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
249. By Simon Fels

Increase UDP send buffer size

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
250. By Simon Fels

Add type definitions for timestamps

251. By Simon Fels

Stop media sender and encoder too when pipeline goes down

252. By Simon Fels

Implement infrastructure for screen/system locks

253. By Simon Fels

Adjust buffer timestamp to respect our framerate

254. By Simon Fels

Further timestamp logging changes

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
255. By Simon Fels

Add cross compilation setup (copied from mir)

256. By Simon Fels

Add some more timestamp logging

257. By Simon Fels

Build with debug configuration

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
258. By Simon Fels

Don't check for matching buffer and just drop the queue head

259. By Simon Fels

Use a buffer queue for the renderer with a max size of two

260. By Simon Fels

Revert substracting a static offset from timestamps

261. By Simon Fels

Stop whole pipeline properly on termination

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
262. By Simon Fels

Correct apparmor rules for our dhcpd use

263. By Simon Fels

We only support extend mode for now

264. By Simon Fels

Properly terminate pipeline for the stream tool

265. By Simon Fels

Add some more statistics we collect over time

266. By Simon Fels

Ignore multiple build folders

267. By Simon Fels

Switch back to same UDP packet size Android uses

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
268. By Simon Fels

Printout a warning when we can't find a optimal video format

269. By Simon Fels

Bring GST based media manager in line with recent changes

270. By Simon Fels

Some more explanation comments

271. By Simon Fels

Fix test source media manager

272. By Simon Fels

Extend logger to be able to set severity on startup

273. By Simon Fels

Have a proper video format fallback instead of invalid values

274. By Simon Fels

Free GLib error messages once done with it

275. By Simon Fels

Let media buffer allocate the memory to transfer ownership

276. By Simon Fels

Implement DisconnectAll manager method

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
277. By Simon Fels

Add unit tests to verify wds video format selection

278. By Simon Fels

tools: install mirscreencast_to_stream utility

279. By Simon Fels

debian: package mirscreencast_to_stream utility too

280. By Simon Fels

debian: add a dependency on -tools for aethercast for now

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
281. By Simon Fels

Do correct video format negotiation

282. By Simon Fels

debian: install additional files we missed before

283. By Simon Fels

Disable power save mode of p2p network interface

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
284. By Simon Fels

Temporarily disable logging of buffer timestamps

285. By Simon Fels

debian: fix apparmor profile extension for dhcpd

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
286. By Simon Fels

Listen on all local addresses for incoming RTSP connection requests

287. By Simon Fels

Set GO intent to 7 and let user change that with an env variable

288. By Simon Fels

Setup a route when running as DHCP server

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
289. By Simon Fels

Select resolution based on env variable

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
290. By Simon Fels

Disable per timestamping according to framerate

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
291. By Simon Fels

Set names for our threads to be able to identify them

292. By Simon Fels

Save statistics for RTP bandwidth

293. By Simon Fels

Print out statistics when our source manager goes down

294. By Simon Fels

Don't produce more frames than we have to

295. By Simon Fels

Sent RTP packets directly to remote via sendto

296. By Simon Fels

Send all RTP packets a TS frames belongs too together

297. By Simon Fels

Allow remote to ask us for an IDR frame

298. By Simon Fels

Check mime type correctly for video/audio prefix

299. By Simon Fels

Correct RTP bandwidth statistics output

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
300. By Simon Fels

Refactor local address assignmnet for source manager

301. By Simon Fels

Enable driver side miracast mode on successful connection

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
302. By Simon Fels

Return an error for a failing scan call

303. By Simon Fels

Don't allow dhcpd to edit our configuration file

304. By Simon Fels

Add support for new wpa API method to send driver commands

305. By Simon Fels

debian: fix apparmor setup

* reload dhcpd profile on startup
* add DAC override for dhcpd to overcome a bug in its package

306. By Simon Fels

Dump additional information for GO negotiation response

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
307. By Simon Fels

Pass correct arguments to dbus error message creation

308. By Simon Fels

Small adjustments to the connect logic

309. By Simon Fels

Limit us to only support 720p with 30 Hz for now

310. By Simon Fels

Print out group negotiation error for easier debugging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
311. By Simon Fels

Format debug message correctly and supply all arguments

312. By Simon Fels

Workaround problems with WDS rate/resolution selection

313. By Simon Fels

Use plain sockets for RTP connection rather than GLib

314. By Simon Fels

Extend GetEnvValue function to be able to return a default value

315. By Simon Fels

Wind local RTP port up the stack and don't use a static one

316. By Simon Fels

Setup miracast source manager when we're connected and not earlier

317. By Simon Fels

Define DHCP server address on construction

318. By Simon Fels

Drop result argument for SendDriverCommand method

319. By Simon Fels

Lock the display when we're connecting until we get disconnected

320. By Simon Fels

Force IPv4 for our DHCP client

321. By Simon Fels

Improve renderer/encoder to really stream a constant framerate

Also optimizes logging in different parts of the code

322. By Simon Fels

Only support CBP with level 3.1 for now

323. By Simon Fels

Trying to resend RTP packages one time and then fail

324. By Simon Fels

Implement missing interface method

325. By Simon Fels

Adjust for WPA DBus API changes

326. By Simon Fels

Don't adjust interface powersave mode

327. By Simon Fels

Keep pointer to management wifi interface

328. By Simon Fels

Refactor code to send private driver commands a bit

329. By Simon Fels

Drop all code for the GL rendering code path which we don't need anymore

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
330. By Simon Fels

Missing changes for cmake configuration

331. By Simon Fels

Drop some more unused code fragments for logging

332. By Simon Fels

Small code cleanups

333. By Simon Fels

Drop unused gstreamer x264 encoder wrapper

334. By Simon Fels

Remove unused system power state controller

335. By Simon Fels

Drop unused unit tests

336. By Simon Fels

Fix encoder class

337. By Simon Fels

Add unit tests for buffer class

338. By Simon Fels

Add video format extraction tests (missing VESA/HH support)

339. By Simon Fels

Correctly release media buffer

340. By Simon Fels

Update WFD IE to indicate a session is not available when connected

341. By Simon Fels

Drop unnecessary dependencies

342. By Simon Fels

Move MediaSender into streaming namespace

343. By Simon Fels

Add interfaces for RTP sender / MPEGTS packetizer classes to make MediaSender testable

344. By Simon Fels

Add unit tests for media sender class

345. By Simon Fels

Add utility function to set thread name

346. By Simon Fels

Add unit test to make sure we're requesting PCR/PAT and PMT

Unmerged revisions

346. By Simon Fels

Add unit test to make sure we're requesting PCR/PAT and PMT

345. By Simon Fels

Add utility function to set thread name

344. By Simon Fels

Add unit tests for media sender class

343. By Simon Fels

Add interfaces for RTP sender / MPEGTS packetizer classes to make MediaSender testable

342. By Simon Fels

Move MediaSender into streaming namespace

341. By Simon Fels

Drop unnecessary dependencies

340. By Simon Fels

Update WFD IE to indicate a session is not available when connected

339. By Simon Fels

Correctly release media buffer

338. By Simon Fels

Add video format extraction tests (missing VESA/HH support)

337. By Simon Fels

Add unit tests for buffer class

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.gitignore'
2--- .gitignore 1970-01-01 00:00:00 +0000
3+++ .gitignore 2016-02-25 12:47:02 +0000
4@@ -0,0 +1,1 @@
5+build*/
6
7=== modified file 'CMakeLists.txt'
8--- CMakeLists.txt 2016-01-12 06:54:24 +0000
9+++ CMakeLists.txt 2016-02-25 12:47:02 +0000
10@@ -54,7 +54,7 @@
11
12 include(cmake/FindReadline.cmake)
13
14-find_package(Boost COMPONENTS filesystem log system thread)
15+find_package(Boost COMPONENTS filesystem log system thread program_options)
16 find_package(PkgConfig)
17 find_package(Threads)
18
19@@ -62,7 +62,19 @@
20 pkg_check_modules(GIO REQUIRED gio-2.0)
21 pkg_check_modules(GIO-UNIX REQUIRED gio-unix-2.0)
22 pkg_check_modules(GST REQUIRED gstreamer-1.0)
23+pkg_check_modules(GST_APP REQUIRED gstreamer-app-1.0)
24 pkg_check_modules(WDS REQUIRED wds)
25+# FIXME for the time being mir is required to do proper hardware
26+# encoding on Android platforms. This will be refactored at some
27+# point to be abstracted by gstreamer completely or made optional.
28+pkg_check_modules(MIRCLIENT REQUIRED mirclient)
29+# Same as mentioned above applies for the hybris and android
30+# things below.
31+pkg_check_modules(HYBRIS_MEDIA REQUIRED libmedia)
32+pkg_check_modules(ANDROID_HEADERS REQUIRED android-headers)
33+pkg_check_modules(EGL REQUIRED egl)
34+pkg_check_modules(GLESV2 REQUIRED glesv2)
35+add_definitions(-DMESA_EGL_NO_X11_HEADERS)
36
37 # Build with system gmock and embedded gtest
38 set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory")
39@@ -78,3 +90,4 @@
40 add_subdirectory(conf)
41 add_subdirectory(src)
42 add_subdirectory(tests)
43+add_subdirectory(tools)
44
45=== added file 'cmake/LinuxCrossCompile.cmake'
46--- cmake/LinuxCrossCompile.cmake 1970-01-01 00:00:00 +0000
47+++ cmake/LinuxCrossCompile.cmake 2016-02-25 12:47:02 +0000
48@@ -0,0 +1,43 @@
49+set(CMAKE_SYSTEM_NAME Linux)
50+set(CMAKE_SYSTEM_VERSION 1)
51+
52+set(AC_NDK_PATH $ENV{AC_NDK_PATH} CACHE STRING "path of mir android bundle")
53+
54+if (NOT DEFINED AC_TARGET_MACHINE)
55+ set(AC_TARGET_MACHINE $ENV{AC_TARGET_MACHINE} CACHE STRING "target machine")
56+endif()
57+if (NOT DEFINED AC_GCC_VARIANT)
58+ set(AC_GCC_VARIANT $ENV{AC_GCC_VARIANT} CACHE STRING "gcc variant required")
59+endif()
60+
61+set(CMAKE_C_COMPILER /usr/bin/${AC_TARGET_MACHINE}-gcc${AC_GCC_VARIANT})
62+set(CMAKE_CXX_COMPILER /usr/bin/${AC_TARGET_MACHINE}-g++${AC_GCC_VARIANT})
63+
64+# where to look to find dependencies in the target environment
65+set(CMAKE_FIND_ROOT_PATH "${AC_NDK_PATH}")
66+
67+#treat the chroot's includes as system includes
68+include_directories(SYSTEM "${AC_NDK_PATH}/usr/include" "${AC_NDK_PATH}/usr/include/${AC_TARGET_MACHINE}")
69+list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${AC_NDK_PATH}/usr/include" "${AC_NDK_PATH}/usr/include/${AC_TARGET_MACHINE}" )
70+
71+# Add the chroot libraries as system libraries
72+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
73+ "${AC_NDK_PATH}/lib"
74+ "${AC_NDK_PATH}/lib/${AC_TARGET_MACHINE}"
75+ "${AC_NDK_PATH}/usr/lib"
76+ "${AC_NDK_PATH}/usr/lib/${AC_TARGET_MACHINE}"
77+)
78+
79+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
80+set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
81+set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG "-Wl,-rpath-link,")
82+set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG "-Wl,-rpath-link,")
83+set(CMAKE_INSTALL_RPATH "${AC_NDK_PATH}/lib:${AC_NDK_PATH}/lib/${AC_TARGET_MACHINE}:${AC_NDK_PATH}/usr/lib:${AC_NDK_PATH}/usr/lib/${AC_TARGET_MACHINE}")
84+
85+set(ENV{PKG_CONFIG_PATH} "${AC_NDK_PATH}/usr/lib/pkgconfig:${AC_NDK_PATH}/usr/lib/${AC_TARGET_MACHINE}/pkgconfig")
86+set(ENV{PKG_CONFIG_SYSROOT_DIR} "${AC_NDK_PATH}")
87+
88+#use only the cross compile system
89+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
90+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
91+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
92
93=== removed file 'conf/dhcpd.conf'
94--- conf/dhcpd.conf 2016-01-16 13:02:21 +0000
95+++ conf/dhcpd.conf 1970-01-01 00:00:00 +0000
96@@ -1,5 +0,0 @@
97-subnet 192.168.7.0 netmask 255.255.255.0 {
98- range 192.168.7.5 192.168.7.10;
99- option subnet-mask 255.255.255.0;
100- option broadcast-address 192.168.7.255;
101-}
102
103=== added file 'cross-compile-chroot.sh'
104--- cross-compile-chroot.sh 1970-01-01 00:00:00 +0000
105+++ cross-compile-chroot.sh 2016-02-25 12:47:02 +0000
106@@ -0,0 +1,163 @@
107+#!/bin/bash
108+# build script to compile Aethercast for armhf devices
109+#
110+set -e
111+
112+usage() {
113+ echo "usage: $(basename $0) [-a <arch>] [-c] [-h] [-d <dist>] [-u]"
114+ echo " -a <arch> Specify target architecture (armhf/arm64/powerpc/ppc64el/amd64/i386/host)"
115+ echo " -c Clean before building"
116+ echo " -d <dist> Select the distribution to build for (vivid/wily/xenial)"
117+ echo " -h This message"
118+ echo " -u Update partial chroot directory"
119+}
120+
121+clean_build_dir() {
122+ rm -rf ${1}
123+ mkdir ${1}
124+}
125+
126+# Default to a dist-agnostic directory name so as to not break Jenkins right now
127+BUILD_DIR=build-android-arm
128+NUM_JOBS=$(( $(grep -c ^processor /proc/cpuinfo) + 1 ))
129+_do_update_chroot=0
130+
131+# Default to vivid as we don't seem to have any working wily devices right now
132+dist=vivid
133+clean=0
134+update_build_dir=0
135+
136+target_arch=armhf
137+
138+while getopts "a:cd:hu" OPTNAME
139+do
140+ case $OPTNAME in
141+ a )
142+ target_arch=${OPTARG}
143+ update_build_dir=1
144+ ;;
145+ c )
146+ clean=1
147+ ;;
148+ d )
149+ dist=${OPTARG}
150+ update_build_dir=1
151+ ;;
152+ u )
153+ _do_update_chroot=1
154+ ;;
155+ h )
156+ usage
157+ exit 0
158+ ;;
159+ : )
160+ echo "Parameter -${OPTARG} needs an argument"
161+ usage
162+ exit 1;
163+ ;;
164+ * )
165+ echo "invalid option specified"
166+ usage
167+ exit 1
168+ ;;
169+ esac
170+done
171+
172+shift $((${OPTIND}-1))
173+
174+if [ "${target_arch}" = "host" ]; then
175+ target_arch=`dpkg-architecture -qDEB_HOST_ARCH`
176+fi
177+
178+if [ ${clean} -ne 0 ]; then
179+ clean_build_dir ${BUILD_DIR}
180+fi
181+
182+if [ ${update_build_dir} -eq 1 ]; then
183+ BUILD_DIR=build-${target_arch}-${dist}
184+fi
185+
186+if [ "${AC_NDK_PATH}" = "" ]; then
187+ export AC_NDK_PATH=~/.cache/aethercast-${target_arch}-chroot-${dist}
188+fi
189+
190+if [ ! -d ${AC_NDK_PATH} ]; then
191+ echo "no partial chroot dir detected. attempting to create one"
192+ _do_update_chroot=1
193+fi
194+
195+if [ ! -d ${BUILD_DIR} ]; then
196+ mkdir ${BUILD_DIR}
197+fi
198+
199+echo "Building for distro: $dist"
200+echo "Using AC_NDK_PATH: ${AC_NDK_PATH}"
201+
202+additional_repositories=
203+if [ ${dist} == "vivid" ] ; then
204+ additional_repositories="-r http://ppa.launchpad.net/ci-train-ppa-service/stable-phone-overlay/ubuntu -r http://ppa.launchpad.net/ci-train-ppa-service/landing-000/ubuntu"
205+fi
206+
207+gcc_variant=
208+if [ "${dist}" = "vivid" ]; then
209+ gcc_variant=-4.9
210+fi
211+
212+case ${target_arch} in
213+ armhf )
214+ target_machine=arm-linux-gnueabihf
215+ ;;
216+ amd64 )
217+ target_machine=x86_64-linux-gnu
218+ ;;
219+ i386 )
220+ target_machine=i386-linux-gnu
221+ ;;
222+ arm64 )
223+ target_machine=aarch64-linux-gnu
224+ ;;
225+ ppc64el )
226+ target_machine=powerpc64le-linux-gnu
227+ ;;
228+ powerpc )
229+ target_machine=powerpc-linux-gnu
230+ ;;
231+ * )
232+ # A good guess (assuming you have dpkg-architecture)
233+ target_machine=`dpkg-architecture -A${target_arch} -qDEB_HOST_MULTIARCH` || {
234+ echo "Unknown architecture ${target_arch}"
235+ usage
236+ exit 1
237+ }
238+ ;;
239+esac
240+
241+echo "Target architecture: ${target_arch}"
242+echo "Target machine: ${target_machine}"
243+
244+if [ ${_do_update_chroot} -eq 1 ] ; then
245+ pushd scripts > /dev/null
246+ ./setup-partial-armhf-chroot.sh -d ${dist} -a ${target_arch} ${additional_repositories} ${AC_NDK_PATH}
247+ popd > /dev/null
248+ # force a clean build after an update, since CMake cache maybe out of date
249+ clean_build_dir ${BUILD_DIR}
250+fi
251+
252+pushd ${BUILD_DIR} > /dev/null
253+
254+ export PKG_CONFIG_PATH="${AC_NDK_PATH}/usr/lib/pkgconfig:${AC_NDK_PATH}/usr/lib/${target_machine}/pkgconfig"
255+ export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
256+ export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
257+ export PKG_CONFIG_SYSROOT_DIR=$AC_NDK_PATH
258+ export PKG_CONFIG_EXECUTABLE=`which pkg-config`
259+ export AC_TARGET_MACHINE=${target_machine}
260+ export AC_GCC_VARIANT=${gcc_variant}
261+ echo "Using PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
262+ echo "Using PKG_CONFIG_EXECUTABLE: $PKG_CONFIG_EXECUTABLE"
263+ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake \
264+ -DCMAKE_BUILD_TYPE=debug \
265+ ..
266+
267+ make -j${NUM_JOBS} $@
268+
269+popd > /dev/null
270
271=== added file 'data/fi.w1.wpa_supplicant1.xml'
272--- data/fi.w1.wpa_supplicant1.xml 1970-01-01 00:00:00 +0000
273+++ data/fi.w1.wpa_supplicant1.xml 2016-02-25 12:47:02 +0000
274@@ -0,0 +1,112 @@
275+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
276+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
277+<node>
278+ <interface name="fi.w1.wpa_supplicant1">
279+ <method name="CreateInterface">
280+ <arg name="args" type="a{sv}" direction="in"/>
281+ <arg name="path" type="o" direction="out"/>
282+ </method>
283+ <signal name="InterfaceAdded">
284+ <arg name="path" type="o"/>
285+ <arg name="properties" type="a{sv}"/>
286+ </signal>
287+ <signal name="InterfaceRemoved">
288+ <arg name="path" type="o"/>
289+ </signal>
290+ <property name="Interfaces" type="ao" access="read"/>
291+ <property name="Capabilities" type="as" access="read"/>
292+ <property name="WFDIEs" type="ay" access="readwrite">
293+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
294+ </property>
295+ </interface>
296+ <interface name="fi.w1.wpa_supplicant1.Interface">
297+ <method name="SendDriverCommand">
298+ <arg name="cmd" type="s" direction="in"/>
299+ </method>
300+ <property name="Capabilities" type="a{sv}" access="read"/>
301+ <property name="State" type="s" access="read"/>
302+ <property name="Ifname" type="s" access="read"/>
303+ <property name="Driver" type="s" access="read"/>
304+ </interface>
305+ <interface name="fi.w1.wpa_supplicant1.Interface.P2PDevice">
306+ <method name="Find">
307+ <arg name="args" type="a{sv}" direction="in"/>
308+ </method>
309+ <method name="StopFind"/>
310+ <method name="ExtendedListen">
311+ <arg name="args" type="a{sv}" direction="in"/>
312+ </method>
313+ <method name="Connect">
314+ <arg name="args" type="a{sv}" direction="in"/>
315+ <arg name="group" type="s" direction="out"/>
316+ </method>
317+ <method name="Cancel"/>
318+ <method name="Disconnect"/>
319+ <method name="Flush"/>
320+ <signal name="DeviceFound">
321+ <arg name="path" type="o"/>
322+ </signal>
323+ <signal name="DeviceLost">
324+ <arg name="path" type="o"/>
325+ </signal>
326+ <signal name="FindStopped"/>
327+ <signal name="GONegotiationSuccess">
328+ <arg name="properties" type="a{sv}"/>
329+ </signal>
330+ <signal name="GONegotiationFailure">
331+ <arg name="properties" type="a{sv}"/>
332+ </signal>
333+ <signal name="GroupStarted">
334+ <arg name="properties" type="a{sv}"/>
335+ </signal>
336+ <signal name="GroupFinished">
337+ <arg name="properties" type="a{sv}"/>
338+ </signal>
339+ <signal name="GroupFormationFailure">
340+ <arg name="reason" type="s"/>
341+ </signal>
342+ <signal name="GONegotiationRequest">
343+ <arg name="path" type="o"/>
344+ <arg name="dev_passwd_id" type="i"/>
345+ </signal>
346+ <property name="P2PDeviceConfig" type="a{sv}" access="readwrite"/>
347+ <property name="Peers" type="ao" access="read"/>
348+ </interface>
349+ <interface name="fi.w1.wpa_supplicant1.Peer">
350+ <property name="DeviceName" type="s" access="read"/>
351+ <property name="Manufacturer" type="s" access="read"/>
352+ <property name="ModelName" type="s" access="read"/>
353+ <property name="ModelNumber" type="s" access="read"/>
354+ <property name="SerialNumber" type="s" access="read"/>
355+ <property name="PrimaryDeviceType" type="ay" access="read"/>
356+ <property name="config_method" type="q" access="read"/>
357+ <property name="level" type="i" access="read"/>
358+ <property name="devicecapability" type="y" access="read"/>
359+ <property name="groupcapability" type="y" access="read"/>
360+ <property name="SecondaryDeviceTypes" type="aay" access="read"/>
361+ <property name="VendorExtension" type="aay" access="read"/>
362+ <property name="IEs" type="ay" access="read"/>
363+ <property name="DeviceAddress" type="ay" access="read">
364+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
365+ </property>
366+ <property name="Groups" type="ao" access="read"/>
367+ </interface>
368+ <interface name="fi.w1.wpa_supplicant1.Group">
369+ <property name="Members" type="s" access="read"/>
370+ <property name="Group" type="o" access="read"/>
371+ <property name="Role" type="s" access="read"/>
372+ <property name="SSID" type="ay" access="read"/>
373+ <property name="BSSID" type="ay" access="read"/>
374+ <property name="Frequency" type="q" access="read"/>
375+ <property name="Passphrase" type="s" access="read"/>
376+ <property name="PSK" type="ay" access="read"/>
377+ <property name="WPSVendorExtensions" type="aay" access="read"/>
378+ <signal name="PeerJoined">
379+ <arg name="peer" type="o"/>
380+ </signal>
381+ <signal name="PeerDisconnected">
382+ <arg name="peer" type="o"/>
383+ </signal>
384+ </interface>
385+</node>
386+
387
388=== removed file 'data/fi.w1.wpa_supplicant1.xml'
389--- data/fi.w1.wpa_supplicant1.xml 2016-01-17 18:42:56 +0000
390+++ data/fi.w1.wpa_supplicant1.xml 1970-01-01 00:00:00 +0000
391@@ -1,109 +0,0 @@
392-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
393- "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
394-<node>
395- <interface name="fi.w1.wpa_supplicant1">
396- <method name="CreateInterface">
397- <arg name="args" type="a{sv}" direction="in"/>
398- <arg name="path" type="o" direction="out"/>
399- </method>
400- <signal name="InterfaceAdded">
401- <arg name="path" type="o"/>
402- <arg name="properties" type="a{sv}"/>
403- </signal>
404- <signal name="InterfaceRemoved">
405- <arg name="path" type="o"/>
406- </signal>
407- <property name="Interfaces" type="ao" access="read"/>
408- <property name="Capabilities" type="as" access="read"/>
409- <property name="WFDIEs" type="ay" access="readwrite">
410- <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
411- </property>
412- </interface>
413- <interface name="fi.w1.wpa_supplicant1.Interface">
414- <property name="Capabilities" type="a{sv}" access="read"/>
415- <property name="State" type="s" access="read"/>
416- <property name="Ifname" type="s" access="read"/>
417- <property name="Driver" type="s" access="read"/>
418- </interface>
419- <interface name="fi.w1.wpa_supplicant1.Interface.P2PDevice">
420- <method name="Find">
421- <arg name="args" type="a{sv}" direction="in"/>
422- </method>
423- <method name="StopFind"/>
424- <method name="ExtendedListen">
425- <arg name="args" type="a{sv}" direction="in"/>
426- </method>
427- <method name="Connect">
428- <arg name="args" type="a{sv}" direction="in"/>
429- <arg name="group" type="s" direction="out"/>
430- </method>
431- <method name="Cancel"/>
432- <method name="Disconnect"/>
433- <method name="Flush"/>
434- <signal name="DeviceFound">
435- <arg name="path" type="o"/>
436- </signal>
437- <signal name="DeviceLost">
438- <arg name="path" type="o"/>
439- </signal>
440- <signal name="FindStopped"/>
441- <signal name="GONegotiationSuccess">
442- <arg name="properties" type="a{sv}"/>
443- </signal>
444- <signal name="GONegotiationFailure">
445- <arg name="properties" type="a{sv}"/>
446- </signal>
447- <signal name="GroupStarted">
448- <arg name="properties" type="a{sv}"/>
449- </signal>
450- <signal name="GroupFinished">
451- <arg name="properties" type="a{sv}"/>
452- </signal>
453- <signal name="GroupFormationFailure">
454- <arg name="reason" type="s"/>
455- </signal>
456- <signal name="GONegotiationRequest">
457- <arg name="path" type="o"/>
458- <arg name="dev_passwd_id" type="i"/>
459- </signal>
460- <property name="P2PDeviceConfig" type="a{sv}" access="readwrite"/>
461- <property name="Peers" type="ao" access="read"/>
462- </interface>
463- <interface name="fi.w1.wpa_supplicant1.Peer">
464- <property name="DeviceName" type="s" access="read"/>
465- <property name="Manufacturer" type="s" access="read"/>
466- <property name="ModelName" type="s" access="read"/>
467- <property name="ModelNumber" type="s" access="read"/>
468- <property name="SerialNumber" type="s" access="read"/>
469- <property name="PrimaryDeviceType" type="ay" access="read"/>
470- <property name="config_method" type="q" access="read"/>
471- <property name="level" type="i" access="read"/>
472- <property name="devicecapability" type="y" access="read"/>
473- <property name="groupcapability" type="y" access="read"/>
474- <property name="SecondaryDeviceTypes" type="aay" access="read"/>
475- <property name="VendorExtension" type="aay" access="read"/>
476- <property name="IEs" type="ay" access="read"/>
477- <property name="DeviceAddress" type="ay" access="read">
478- <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
479- </property>
480- <property name="Groups" type="ao" access="read"/>
481- </interface>
482- <interface name="fi.w1.wpa_supplicant1.Group">
483- <property name="Members" type="s" access="read"/>
484- <property name="Group" type="o" access="read"/>
485- <property name="Role" type="s" access="read"/>
486- <property name="SSID" type="ay" access="read"/>
487- <property name="BSSID" type="ay" access="read"/>
488- <property name="Frequency" type="q" access="read"/>
489- <property name="Passphrase" type="s" access="read"/>
490- <property name="PSK" type="ay" access="read"/>
491- <property name="WPSVendorExtensions" type="aay" access="read"/>
492- <signal name="PeerJoined">
493- <arg name="peer" type="o"/>
494- </signal>
495- <signal name="PeerDisconnected">
496- <arg name="peer" type="o"/>
497- </signal>
498- </interface>
499-</node>
500-
501
502=== modified file 'data/org.aethercast.xml'
503--- data/org.aethercast.xml 2015-12-10 17:13:50 +0000
504+++ data/org.aethercast.xml 2016-02-25 12:47:02 +0000
505@@ -9,6 +9,8 @@
506 <arg name="path" type="o" direction="in"/>
507 </method>
508 <method name="Scan"/>
509+ <!-- FIXME just for demo purposes. Don't use this method. -->
510+ <method name="DisconnectAll"/>
511 <property name="State" type="s" access="read"/>
512 <property name="Capabilities" type="as" access="read"/>
513 <property name="Scanning" type="b" access="read"/>
514
515=== added file 'debian/aethercast-tools.install'
516--- debian/aethercast-tools.install 1970-01-01 00:00:00 +0000
517+++ debian/aethercast-tools.install 2016-02-25 12:47:02 +0000
518@@ -0,0 +1,1 @@
519+usr/bin/mirscreencast_to_stream
520
521=== removed file 'debian/aethercast.install'
522--- debian/aethercast.install 2016-01-17 14:08:15 +0000
523+++ debian/aethercast.install 1970-01-01 00:00:00 +0000
524@@ -1,1 +0,0 @@
525-debian/usr.sbin.aethercast /etc/apparmor.d/dhcpd.d/
526
527=== modified file 'debian/control'
528--- debian/control 2016-01-21 11:13:32 +0000
529+++ debian/control 2016-02-25 12:47:02 +0000
530@@ -3,24 +3,31 @@
531 Priority: optional
532 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
533 XSBC-Original-Maintainer: Simon Fels <simon.fels@canonical.com>
534-Build-Depends: cmake,
535+Build-Depends: android-headers-19 (>= 23),
536+ cmake,
537 debhelper (>= 9),
538+ dh-apparmor,
539 dbus,
540 google-mock,
541 libboost-dev,
542 libboost-filesystem-dev,
543 libboost-log-dev,
544 libboost-iostreams-dev,
545+ libboost-program-options-dev,
546 libboost-system-dev,
547 # boost log needs exactly one symbol from boost-thread for resolving
548 # thread-specific storage locations.
549 libboost-thread-dev,
550 libglib2.0-dev,
551 libgstreamer1.0-dev,
552+ libgstreamer-plugins-base1.0-dev,
553 libgtest-dev,
554+ libhybris-dev,
555+ libmedia-dev,
556 libreadline-dev,
557 libreadline6-dev,
558- libwds-dev
559+ libwds-dev,
560+ pkg-config
561 Standards-Version: 3.9.4
562 Homepage: http://launchpad.net/aethercast
563 # If you aren't a member of ~phablet-team but need to upload packaging changes,
564@@ -29,9 +36,10 @@
565 Vcs-Browser: http://bazaar.launchpad.net/aethercast/trunk/files
566
567 Package: aethercast
568-Architecture: any
569+Architecture: i386 amd64 armhf
570 Depends: ${misc:Depends},
571 ${shlibs:Depends},
572+ aethercast-tools,
573 isc-dhcp-server,
574 isc-dhcp-client,
575 wpasupplicant
576@@ -39,3 +47,18 @@
577 A management service for remote displays which it can stream the
578 current screen content to. It will support multiple approaches
579 for this like Miracast.
580+
581+Package: aethercast-tools
582+Architecture: i386 amd64 armhf
583+Depends: ${misc:Depends},
584+ ${shlibs:Depends},
585+ isc-dhcp-server,
586+ isc-dhcp-client,
587+ wpasupplicant
588+Description: Tools for the display casting service
589+ A management service for remote displays which it can stream the
590+ current screen content to. It will support multiple approaches
591+ for this like Miracast.
592+ .
593+ This package contains small utilities helping to work with the
594+ display streaming stack.
595
596=== modified file 'debian/rules'
597--- debian/rules 2016-01-17 14:01:37 +0000
598+++ debian/rules 2016-02-25 12:47:02 +0000
599@@ -20,3 +20,7 @@
600
601 override_dh_auto_test:
602 # disable
603+
604+override_dh_install:
605+ dh_install
606+ dh_apparmor -paethercast --profile-name=usr.sbin.dhcpd
607
608=== modified file 'debian/usr.sbin.aethercast'
609--- debian/usr.sbin.aethercast 2016-01-30 12:33:55 +0000
610+++ debian/usr.sbin.aethercast 2016-02-25 12:47:02 +0000
611@@ -1,11 +1,15 @@
612 # vim:syntax=apparmor
613
614- # Allow aethercast to start dhcpd with its own configuration
615- # file it needs to provide DHCP for groups it manages through
616- # WiFi Direct. This need to stay as long as NetworkManager does
617- # not has support for WiFi Direct and aethercast is using that.
618- /etc/aethercast/dhcpd.conf r,
619- # In addition aethercast will also point dhcpd to a private
620- # lease/pid file
621- /{,var/}run/aethercast/dhcpd*.leases* lrw,
622- /{,var/}run/aethercast/dhcpd*.pid lrw,
623+# Work around bug:
624+# https://bugs.launchpad.net/ubuntu/+source/isc-dhcp/+bug/1186662
625+capability dac_override,
626+
627+# Allow aethercast to start dhcpd with its own configuration
628+# file it needs to provide DHCP for groups it manages through
629+# WiFi Direct. This need to stay as long as NetworkManager does
630+# not has support for WiFi Direct and aethercast is using that.
631+/etc/aethercast/dhcpd.conf r,
632+# In addition aethercast will also point dhcpd to a private
633+# lease/pid file
634+/{,var/}run/aethercast/dhcpd*.leases lrw,
635+/{,var/}run/aethercast/dhcpd*.pid lrw,
636
637=== added directory 'scripts'
638=== added file 'scripts/setup-partial-armhf-chroot.sh'
639--- scripts/setup-partial-armhf-chroot.sh 1970-01-01 00:00:00 +0000
640+++ scripts/setup-partial-armhf-chroot.sh 2016-02-25 12:47:02 +0000
641@@ -0,0 +1,155 @@
642+#!/bin/bash
643+#
644+# TODO: Rename this file without "armhf" when it's safe to do so.
645+#
646+
647+set -e
648+
649+name=${0}
650+
651+usage() {
652+ echo "Usage: ${name} [options] mychroot-dir"
653+ echo "options:"
654+ echo " -a arch Select architecture, i.e. armhf, arm64, ppc... Default is armhf"
655+ echo " -d dist Select distribution, i.e. vivid, wily. Default is vivid"
656+ echo " -r rep Select an additional repository for bootstrap. Default is none"
657+ echo
658+ echo "please supply at least a directory to create partial chroot in. (eg, ./setup-partial-armhf-chroot.sh mychroot-dir)"
659+}
660+
661+# Default to vivid as we don't seem to have any working wily devices right now.
662+# Also Jenkins expects this script to default to vivid (TODO: update CI?)
663+arch=armhf
664+dist=vivid
665+sourceid=0
666+repositories=
667+sources=
668+
669+while getopts a:d:r:h opt; do
670+ case $opt in
671+ a)
672+ arch=$OPTARG
673+ ;;
674+ d)
675+ dist=$OPTARG
676+ ;;
677+ r)
678+ repositories="$repositories $OPTARG"
679+ ((++sourceid))
680+ sources="$sources source$sourceid"
681+ ;;
682+ :)
683+ echo "Option -$OPTARG requires an argument"
684+ usage
685+ exit 1
686+ ;;
687+ h)
688+ usage
689+ exit 0
690+ ;;
691+ \?)
692+ echo "Invalid option: -$OPTARG"
693+ usage
694+ exit 1
695+ ;;
696+ esac
697+done
698+
699+shift $((OPTIND-1))
700+
701+if [ -z ${1} ]; then
702+ usage
703+ exit 1
704+fi
705+
706+directory=${1}
707+echo "creating phablet-compatible $arch partial chroot for aethercast compilation in directory ${directory}"
708+
709+if [ ! -d ${directory} ]; then
710+ mkdir -p ${directory}
711+fi
712+
713+DEBCONTROL=$(pwd)/../debian/control
714+
715+pushd ${directory} > /dev/null
716+
717+# Empty dpkg status file, so that ALL dependencies are listed with dpkg-checkbuilddeps
718+echo "" > status
719+
720+# Manual error code checking is needed for dpkg-checkbuilddeps
721+set +e
722+
723+# Parse dependencies from debian/control
724+# dpkg-checkbuilddeps returns non-zero when dependencies are not met and the list is sent to stderr
725+builddeps=$(dpkg-checkbuilddeps -a ${arch} --admindir=. ${DEBCONTROL} 2>&1 )
726+if [ $? -eq 0 ] ; then
727+ exit 0
728+fi
729+echo "${builddeps}"
730+
731+# now turn exit on error option
732+set -e
733+
734+# Sanitize dependencies list for submission to multistrap
735+# build-essential is not needed as we are cross-compiling
736+builddeps=$(echo ${builddeps} | sed -e 's/dpkg-checkbuilddeps://g' \
737+ -e 's/error://g' \
738+ -e 's/Unmet build dependencies://g' \
739+ -e 's/build-essential:native//g')
740+builddeps=$(echo ${builddeps} | sed 's/([^)]*)//g')
741+builddeps=$(echo ${builddeps} | sed -e 's/abi-compliance-checker//g')
742+builddeps=$(echo ${builddeps} | sed -e 's/multistrap//g')
743+
744+case ${arch} in
745+ amd64 | i386 )
746+ source_url=http://archive.ubuntu.com/ubuntu
747+ ;;
748+ * )
749+ source_url=http://ports.ubuntu.com/ubuntu-ports
750+ ;;
751+esac
752+
753+echo "[General]
754+arch=${arch}
755+directory=${directory}
756+unpack=false
757+noauth=true
758+bootstrap=Ubuntu ${sources}
759+
760+[Ubuntu]
761+packages=${builddeps}
762+source=${source_url}
763+suite=${dist}
764+" > mstrap.conf
765+
766+sourceid=0
767+for x in ${repositories};
768+do
769+ ((++sourceid))
770+ echo "[source${sourceid}]
771+source=${x}
772+suite=${dist}
773+" >> mstrap.conf
774+done
775+
776+multistrap -f mstrap.conf
777+
778+rm -f var/cache/apt/archives/lock
779+
780+# Remove libc libraries that confuse the cross-compiler
781+rm -f var/cache/apt/archives/libc-dev*.deb
782+rm -f var/cache/apt/archives/libc6*.deb
783+
784+for deb in var/cache/apt/archives/* ; do
785+ if [ ! -d ${deb} ] ; then
786+ echo "unpacking: ${deb}"
787+ dpkg -x ${deb} .
788+ fi
789+done
790+
791+# Fix up symlinks which asssumed the usual root path
792+for broken_symlink in $(find . -name \*.so -type l -xtype l) ; do
793+ ln -sf $(pwd)$(readlink ${broken_symlink}) ${broken_symlink}
794+done
795+
796+popd > /dev/null
797
798=== modified file 'src/CMakeLists.txt'
799--- src/CMakeLists.txt 2016-01-21 13:25:31 +0000
800+++ src/CMakeLists.txt 2016-02-25 12:47:02 +0000
801@@ -27,15 +27,17 @@
802 configure_file(w11tng/config.h.in w11tng/config.h @ONLY)
803
804 set(HEADERS
805- mcs/ip_v4_address.h
806- mcs/keep_alive.h
807- mcs/mac_address.h
808- mcs/types.h
809- mcs/shared_gobject.h
810- mcs/keep_alive.h
811-
812- mcs/config.h
813- w11tng/config.h
814+ mcs/ip_v4_address.h
815+ mcs/keep_alive.h
816+ mcs/mac_address.h
817+ mcs/types.h
818+ mcs/shared_gobject.h
819+ mcs/keep_alive.h
820+ mcs/config.h
821+
822+ mcs/gl/common.h
823+
824+ w11tng/config.h
825 )
826
827 set(SOURCES
828@@ -43,11 +45,11 @@
829 mcs/networkutils.cpp
830 mcs/mediamanagerfactory.cpp
831 mcs/basesourcemediamanager.cpp
832+ mcs/initgstreameronce.cpp
833 mcs/gstsourcemediamanager.cpp
834 mcs/testsourcemediamanager.cpp
835 mcs/x11sourcemediamanager.cpp
836 mcs/logger.cpp
837- mcs/mirsourcemediamanager.cpp
838 mcs/forwardingmiracastcontroller.cpp
839 mcs/forwardingnetworkdevice.cpp
840 mcs/miracastcontroller.cpp
841@@ -58,11 +60,39 @@
842 mcs/networkmanager.cpp
843 mcs/networkmanagerfactory.cpp
844 mcs/networkdevice.cpp
845-
846+ mcs/x264.cpp
847 ${CMAKE_CURRENT_BINARY_DIR}/mcs/aethercastinterface.c
848 mcs/dbushelpers.cpp
849 mcs/networkdeviceskeleton.cpp
850
851+ mcs/video/videoformat.cpp
852+ mcs/video/buffer.cpp
853+ mcs/video/bufferqueue.cpp
854+ mcs/video/utils.cpp
855+ mcs/video/utils_from_android.cpp
856+ mcs/video/baseencoder.cpp
857+ mcs/video/h264analyzer.cpp
858+ mcs/video/measurepoint.cpp
859+ mcs/video/statistics.cpp
860+
861+ mcs/streaming/mpegtspacketizer.cpp
862+ mcs/streaming/rtpsender.cpp
863+
864+ mcs/mir/mediasender.cpp
865+ mcs/mir/sourcemediamanagernext.cpp
866+ mcs/mir/streamconnector.cpp
867+ mcs/mir/streamrenderer.cpp
868+
869+ mcs/android/h264encoder.cpp
870+
871+ mcs/systemcontroller.cpp
872+
873+ mcs/ubuntu/powerd.cpp
874+ mcs/ubuntu/unity.cpp
875+ mcs/ubuntu/systemcontroller.cpp
876+ mcs/ubuntu/powerdsystemlock.cpp
877+ mcs/ubuntu/unitydisplaylock.cpp
878+
879 ${CMAKE_CURRENT_BINARY_DIR}/mcs/wpasupplicantinterface.c
880 w11tng/networkmanager.cpp
881 w11tng/networkdevice.cpp
882@@ -83,20 +113,19 @@
883 w11tng/hostname1stub.cpp
884 )
885
886-link_directories(
887- ${GLIB_LIBRARY_DIRS}
888- ${GIO_LIBRARY_DIRS}
889- ${GIO-UNIX_LIBRARY_DIRS}
890- ${WDS_LIBRARY_DIRS}
891-)
892-
893 include_directories(
894 ${Boost_INCLUDE_DIRS}
895 ${GLIB_INCLUDE_DIRS}
896 ${GIO_INCLUDE_DIRS}
897 ${GIO-UNIX_INCLUDE_DIRS}
898 ${GST_INCLUDE_DIRS}
899+ ${GST_APP_INCLUDE_DIRS}
900 ${WDS_INCLUDE_DIRS}
901+ ${HYBRIS_MEDIA_INCLDUE_DIRS}
902+ ${ANDROID_HEADERS_INCLUDE_DIRS}
903+ ${MIRCLIENT_INCLUDE_DIRS}
904+ ${EGL_INCLUDE_DIRS}
905+ ${GLESV2_INCLUDE_DIRS}
906 ${CMAKE_CURRENT_BINARY_DIR}/src
907 ${CMAKE_CURRENT_BINARY_DIR}/src/w11tng
908 )
909@@ -106,13 +135,29 @@
910 add_executable(aethercast mcs/main.cpp)
911
912 target_link_libraries(aethercast-core
913+ ${Boost_LDFLAGS}
914 ${Boost_LIBRARIES}
915+ ${GLIB_LDFLAGS}
916 ${GLIB_LIBRARIES}
917+ ${GIO_LDFLAGS}
918 ${GIO_LIBRARIES}
919+ ${GIO-UNIX_LDFLAGS}
920 ${GIO-UNIX_LIBRARIES}
921+ ${GST_LDFLAGS}
922 ${GST_LIBRARIES}
923+ ${GST_APP_LDFLAGS}
924+ ${GST_APP_LIBRARIES}
925 ${CMAKE_THREAD_LIBS_INIT}
926+ ${WDS_LDFLAGS}
927 ${WDS_LIBRARIES}
928+ ${HYBRIS_MEDIA_LDFLAGS}
929+ ${HYBRIS_MEDIA_LIBRARIES}
930+ ${MIRCLIENT_LDFLAGS}
931+ ${MIRCLIENT_LIBRARIES}
932+ ${EGL_LDFLAGS}
933+ ${EGL_LIBRARIES}
934+ ${GLESV2_LDFLAGS}
935+ ${GLESV2_LIBRARIES}
936 -ldl
937 )
938
939
940=== added directory 'src/mcs/android'
941=== added file 'src/mcs/android/h264encoder.cpp'
942--- src/mcs/android/h264encoder.cpp 1970-01-01 00:00:00 +0000
943+++ src/mcs/android/h264encoder.cpp 2016-02-25 12:47:02 +0000
944@@ -0,0 +1,464 @@
945+/*
946+ * Copyright (C) 2016 Canonical, Ltd.
947+ *
948+ * This program is free software: you can redistribute it and/or modify it
949+ * under the terms of the GNU General Public License version 3, as published
950+ * by the Free Software Foundation.
951+ *
952+ * This program is distributed in the hope that it will be useful, but
953+ * WITHOUT ANY WARRANTY; without even the implied warranties of
954+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
955+ * PURPOSE. See the GNU General Public License for more details.
956+ *
957+ * You should have received a copy of the GNU General Public License along
958+ * with this program. If not, see <http://www.gnu.org/licenses/>.
959+ *
960+ */
961+
962+#include <system/window.h>
963+
964+#include "mcs/logger.h"
965+
966+#include "mcs/video/statistics.h"
967+
968+#include "mcs/android/h264encoder.h"
969+
970+namespace {
971+static const char *kEncoderThreadName{"H264Encoder"};
972+static const char *kH264MimeType{"video/avc"};
973+static const char *kRawMimeType{"video/raw"};
974+// From frameworks/native/include/media/openmax/OMX_IVCommon.h
975+const int32_t kOMXColorFormatAndroidOpaque = 0x7F000789;
976+const int32_t kOMXVideoIntraRefreshCyclic = 0;
977+// From frameworks/native/include/media/openmax/OMX_Video.h
978+const int32_t kOMXVideoControlRateConstant = 2;
979+// From frameworks/native/include/media/hardware/MetadataBufferType.h
980+const uint32_t kMetadataBufferTypeGrallocSource = 1;
981+// From frameworks/av/include/media/stagefright/MediaErrors.h
982+enum AndroidMediaError {
983+ kAndroidMediaErrorBase = -1000,
984+ kAndroidMediaErrorEndOfStream = kAndroidMediaErrorBase - 11,
985+};
986+}
987+
988+namespace mcs {
989+namespace android {
990+
991+class MediaSourceBuffer : public video::Buffer
992+{
993+public:
994+ typedef std::shared_ptr<MediaSourceBuffer> Ptr;
995+
996+ ~MediaSourceBuffer() {
997+ if (!buffer_)
998+ return;
999+
1000+ auto ref_count = media_buffer_get_refcount(buffer_);
1001+
1002+ // If someone has set a reference on the buffer we just have to
1003+ // release it here and the other one will take care about actually
1004+ // destroying it.
1005+ if (ref_count > 0)
1006+ media_buffer_release(buffer_);
1007+ else
1008+ media_buffer_destroy(buffer_);
1009+
1010+ }
1011+
1012+ static MediaSourceBuffer::Ptr Create(MediaBufferWrapper *buffer) {
1013+ auto sp = std::shared_ptr<MediaSourceBuffer>(new MediaSourceBuffer);
1014+ sp->buffer_ = buffer;
1015+ sp->ExtractTimestamp();
1016+ return sp;
1017+ }
1018+
1019+ virtual uint32_t Length() const {
1020+ if (!buffer_)
1021+ return 0;
1022+
1023+ return media_buffer_get_size(buffer_);
1024+ }
1025+
1026+ virtual uint8_t* Data() {
1027+ if (!buffer_)
1028+ return nullptr;
1029+
1030+ return static_cast<uint8_t*>(media_buffer_get_data(buffer_));
1031+ }
1032+
1033+ virtual bool IsValid() const {
1034+ return buffer_ != nullptr;
1035+ }
1036+
1037+private:
1038+ MediaSourceBuffer() { }
1039+
1040+ void ExtractTimestamp() {
1041+ auto meta_data = media_buffer_get_meta_data(buffer_);
1042+ if (!meta_data)
1043+ return;
1044+
1045+ uint32_t key_time = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_TIME);
1046+ int64_t time_us = 0;
1047+ media_meta_data_find_int64(meta_data, key_time, &time_us);
1048+
1049+ SetTimestamp(time_us);
1050+ }
1051+
1052+private:
1053+ MediaBufferWrapper *buffer_;
1054+};
1055+
1056+video::BaseEncoder::Config H264Encoder::DefaultConfiguration() {
1057+ Config config;
1058+ // Supplying -1 as framerate means the encoder decides on what it
1059+ // can provide.
1060+ config.framerate = -1;
1061+ config.bitrate = 5000000;
1062+ config.i_frame_interval = 15;
1063+ config.intra_refresh_mode = kOMXVideoIntraRefreshCyclic;
1064+ return config;
1065+}
1066+
1067+H264Encoder::Ptr H264Encoder::Create() {
1068+ return std::shared_ptr<H264Encoder>(new H264Encoder);
1069+}
1070+
1071+H264Encoder::H264Encoder() :
1072+ format_(nullptr),
1073+ encoder_(nullptr),
1074+ running_(false),
1075+ input_queue_(mcs::video::BufferQueue::Create()),
1076+ start_time_(-1ll),
1077+ frame_count_(0) {
1078+}
1079+
1080+H264Encoder::~H264Encoder() {
1081+ Stop();
1082+
1083+ if (encoder_)
1084+ media_codec_source_release(encoder_);
1085+
1086+ if (source_)
1087+ delete source_; /* media_source_release(source_); */
1088+
1089+ if (format_)
1090+ media_message_release(format_);
1091+}
1092+
1093+bool H264Encoder::IsValid() const {
1094+ return true;
1095+}
1096+
1097+bool H264Encoder::Configure(const Config &config) {
1098+ if (encoder_)
1099+ return false;
1100+
1101+ MCS_DEBUG("configuring with %dx%d@%d", config.width, config.height, config.framerate);
1102+
1103+ auto format = media_message_create();
1104+ if (!format)
1105+ return false;
1106+
1107+ media_message_set_string(format, "mime", kH264MimeType, 0);
1108+
1109+ media_message_set_int32(format, "store-metadata-in-buffers", true);
1110+ media_message_set_int32(format, "store-metadata-in-buffers-output", false);
1111+
1112+ media_message_set_int32(format, "width", config.width);
1113+ media_message_set_int32(format, "height", config.height);
1114+ media_message_set_int32(format, "stride", config.width);
1115+ media_message_set_int32(format, "slice-height", config.width);
1116+
1117+ media_message_set_int32(format, "color-format", kOMXColorFormatAndroidOpaque);
1118+
1119+ media_message_set_int32(format, "bitrate", config.bitrate);
1120+ media_message_set_int32(format, "bitrate-mode", kOMXVideoControlRateConstant);
1121+ media_message_set_int32(format, "frame-rate", config.framerate);
1122+
1123+ media_message_set_int32(format, "intra-refresh-mode", 0);
1124+
1125+ // Update macroblocks in a cyclic fashion with 10% of all MBs within
1126+ // frame gets updated at one time. It takes about 10 frames to
1127+ // completely update a whole video frame. If the frame rate is 30,
1128+ // it takes about 333 ms in the best case (if next frame is not an IDR)
1129+ // to recover from a lost/corrupted packet.
1130+ int32_t mbs = (((config.width + 15) / 16) * ((config.height + 15) / 16) * 10) / 100;
1131+ media_message_set_int32(format, "intra-refresh-CIR-mbs", mbs);
1132+
1133+ if (config.i_frame_interval > 0)
1134+ media_message_set_int32(format, "i-frame-interval", config.i_frame_interval);
1135+
1136+ if (config.profile_idc > 0)
1137+ media_message_set_int32(format, "profile-idc", config.profile_idc);
1138+
1139+ if (config.level_idc > 0)
1140+ media_message_set_int32(format, "level-idc", config.level_idc);
1141+
1142+ if (config.constraint_set > 0)
1143+ media_message_set_int32(format, "constraint-set", config.constraint_set);
1144+
1145+ // FIXME we need to find a way to check if the encoder supports prepending
1146+ // SPS/PPS to the buffers it is producing or if we have to manually do that
1147+ media_message_set_int32(format, "prepend-sps-pps-to-idr-frames", 1);
1148+
1149+ source_ = media_source_create();
1150+ if (!source_) {
1151+ MCS_ERROR("Failed to create media input source for encoder");
1152+ media_message_release(format);
1153+ return false;
1154+ }
1155+
1156+ auto source_format = media_meta_data_create();
1157+
1158+ // Notice that we're passing video/raw as mime type here which is quite
1159+ // important to let the encoder do the right thing with the incoming data
1160+ media_meta_data_set_cstring(source_format,
1161+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_MIME),
1162+ kRawMimeType);
1163+
1164+ // We're setting the opaque color format here as the encoder is then
1165+ // meant to figure out the color format from the GL frames itself.
1166+ media_meta_data_set_int32(source_format,
1167+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_COLOR_FORMAT),
1168+ kOMXColorFormatAndroidOpaque);
1169+
1170+ media_meta_data_set_int32(source_format,
1171+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_WIDTH),
1172+ config.width);
1173+ media_meta_data_set_int32(source_format,
1174+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_HEIGHT),
1175+ config.height);
1176+ media_meta_data_set_int32(source_format,
1177+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_STRIDE),
1178+ config.width);
1179+ media_meta_data_set_int32(source_format,
1180+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_SLICE_HEIGHT),
1181+ config.height);
1182+ media_meta_data_set_int32(source_format,
1183+ media_meta_data_get_key_id(MEDIA_META_DATA_KEY_FRAMERATE),
1184+ config.framerate);
1185+
1186+ media_source_set_format(source_, source_format);
1187+
1188+ media_source_set_start_callback(source_, &H264Encoder::OnSourceStart, this);
1189+ media_source_set_stop_callback(source_, &H264Encoder::OnSourceStop, this);
1190+ media_source_set_read_callback(source_, &H264Encoder::OnSourceRead, this);
1191+ media_source_set_pause_callback(source_, &H264Encoder::OnSourcePause, this);
1192+
1193+ encoder_ = media_codec_source_create(format, source_, 0);
1194+ if (!encoder_) {
1195+ MCS_ERROR("Failed to create encoder instance");
1196+ return false;
1197+ }
1198+
1199+ config_ = config;
1200+ format_ = format;
1201+
1202+ MCS_DEBUG("Configured encoder succesfully");
1203+
1204+ return true;
1205+}
1206+
1207+void H264Encoder::Start() {
1208+ if (!encoder_ || running_)
1209+ return;
1210+
1211+ if (!media_codec_source_start(encoder_)) {
1212+ MCS_ERROR("Failed to start encoder");
1213+ return;
1214+ }
1215+
1216+ worker_thread_ = std::thread(&H264Encoder::WorkerThread, this);
1217+ pthread_setname_np(worker_thread_.native_handle(), kEncoderThreadName);
1218+
1219+ running_ = true;
1220+
1221+ MCS_DEBUG("Started encoder");
1222+}
1223+
1224+int H264Encoder::OnSourceStart(MediaMetaDataWrapper *meta, void *user_data) {
1225+ auto thiz = static_cast<H264Encoder*>(user_data);
1226+
1227+ MCS_DEBUG("");
1228+
1229+ return 0;
1230+}
1231+
1232+int H264Encoder::OnSourceStop(void *user_data) {
1233+ auto thiz = static_cast<H264Encoder*>(user_data);
1234+
1235+ MCS_DEBUG("");
1236+
1237+ return 0;
1238+}
1239+
1240+MediaBufferWrapper* H264Encoder::PackBuffer(const mcs::video::Buffer::Ptr &input_buffer, const mcs::TimestampUs &timestamp) {
1241+ if (!input_buffer->NativeHandle()) {
1242+ MCS_WARNING("Ignoring buffer without native handle");
1243+ return nullptr;
1244+ }
1245+
1246+ auto anwb = reinterpret_cast<ANativeWindowBuffer*>(input_buffer->NativeHandle());
1247+
1248+ size_t size = sizeof(buffer_handle_t) + 4;
1249+
1250+ // We let the media buffer allocate the memory here to let it keep
1251+ // the ownership and release the memory once its destroyed.
1252+ auto buffer = media_buffer_create(size);
1253+ auto data = media_buffer_get_data(buffer);
1254+
1255+ // We're passing the buffer handle directly as part of the buffer data
1256+ // here to the encoder and it will figure out it has to deal with a
1257+ // buffer with the key value we put in front of it. See also
1258+ // frameworks/av/media/libstagefright/SurfaceMediaSource.cpp for more
1259+ // details about this.
1260+ uint32_t type = kMetadataBufferTypeGrallocSource;
1261+ memcpy(data, &type, 4);
1262+ memcpy(data + 4, &anwb->handle, sizeof(buffer_handle_t));
1263+
1264+ media_buffer_set_return_callback(buffer, &H264Encoder::OnBufferReturned, this);
1265+
1266+ // We need to put a reference on the buffer here if we want the
1267+ // callback we set above being called.
1268+ media_buffer_ref(buffer);
1269+
1270+ auto meta = media_buffer_get_meta_data(buffer);
1271+ auto key_time = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_TIME);
1272+ media_meta_data_set_int64(meta, key_time, timestamp);
1273+
1274+ pending_buffers_.push_back(BufferItem{input_buffer, buffer});
1275+
1276+ return buffer;
1277+}
1278+
1279+int H264Encoder::OnSourceRead(MediaBufferWrapper **buffer, void *user_data) {
1280+ auto thiz = static_cast<H264Encoder*>(user_data);
1281+
1282+ auto input_buffer = thiz->input_queue_->Next();
1283+
1284+
1285+ auto next_buffer = thiz->PackBuffer(input_buffer, input_buffer->Timestamp());
1286+
1287+ if (!next_buffer)
1288+ return kAndroidMediaErrorEndOfStream;
1289+
1290+ *buffer = next_buffer;
1291+
1292+ return 0;
1293+}
1294+
1295+int H264Encoder::OnSourcePause(void *user_data) {
1296+ auto thiz = static_cast<H264Encoder*>(user_data);
1297+
1298+ MCS_DEBUG("");
1299+
1300+ return 0;
1301+}
1302+
1303+void H264Encoder::OnBufferReturned(MediaBufferWrapper *buffer, void *user_data) {
1304+ auto thiz = static_cast<H264Encoder*>(user_data);
1305+
1306+ // Find the right pending buffer matching the returned one
1307+ auto iter = thiz->pending_buffers_.begin();
1308+ for (; iter != thiz->pending_buffers_.end(); ++iter) {
1309+ if (iter->media_buffer == buffer)
1310+ break;
1311+ }
1312+
1313+ if (iter == thiz->pending_buffers_.end()) {
1314+ MCS_WARNING("Didn't remember returned buffer!?");
1315+ return;
1316+ }
1317+
1318+ // Unset observer to be able to call release on the MediaBuffer
1319+ // and reduce its reference count. It has an internal check if
1320+ // an observer is still set or not before it will actually release
1321+ // itself.
1322+ media_buffer_set_return_callback(iter->media_buffer, nullptr, nullptr);
1323+ media_buffer_release(iter->media_buffer);
1324+
1325+ auto buf = iter->buffer;
1326+ thiz->pending_buffers_.erase(iter);
1327+
1328+ // After we've cleaned up everything we can send the buffer
1329+ // back to the producer which then can reuse it.
1330+ buf->Release();
1331+}
1332+
1333+bool H264Encoder::DoesBufferContainCodecConfig(MediaBufferWrapper *buffer) {
1334+ auto meta_data = media_buffer_get_meta_data(buffer);
1335+ if (!meta_data)
1336+ return false;
1337+
1338+ uint32_t key_is_codec_config = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_IS_CODEC_CONFIG);
1339+ int32_t is_codec_config = 0;
1340+ media_meta_data_find_int32(meta_data, key_is_codec_config, &is_codec_config);
1341+ return static_cast<bool>(is_codec_config);
1342+}
1343+
1344+void H264Encoder::WorkerThread() {
1345+ MCS_DEBUG("Encoder worker thread is running");
1346+
1347+ while (running_) {
1348+ MediaBufferWrapper *buffer = nullptr;
1349+ if (!media_codec_source_read(encoder_, &buffer)) {
1350+ MCS_ERROR("Failed to read a new buffer from encoder");
1351+ return;
1352+ }
1353+
1354+ auto mbuf = MediaSourceBuffer::Create(buffer);
1355+
1356+ if (mbuf->Timestamp() > 0) {
1357+ int64_t now = mcs::Utils::GetNowUs();
1358+ int64_t diff = (now - mbuf->Timestamp()) / 1000ll;
1359+ video::Statistics::Instance()->RecordEncoderBufferOut(diff);
1360+ }
1361+
1362+ if (DoesBufferContainCodecConfig(buffer)) {
1363+ if (auto sp = delegate_.lock())
1364+ sp->OnBufferWithCodecConfig(mbuf);
1365+ }
1366+
1367+ if (auto sp = delegate_.lock())
1368+ sp->OnBufferAvailable(mbuf);
1369+ }
1370+}
1371+
1372+void H264Encoder::Stop() {
1373+ if (!encoder_ || !running_)
1374+ return;
1375+
1376+ if (!media_codec_source_stop(encoder_))
1377+ return;
1378+
1379+ running_ = false;
1380+ worker_thread_.join();
1381+}
1382+
1383+void H264Encoder::QueueBuffer(const video::Buffer::Ptr &buffer) {
1384+ input_queue_->Push(buffer);
1385+}
1386+
1387+void* H264Encoder::NativeWindowHandle() const {
1388+ if (!encoder_)
1389+ return nullptr;
1390+
1391+ return media_codec_source_get_native_window_handle(encoder_);
1392+}
1393+
1394+video::BaseEncoder::Config H264Encoder::Configuration() const {
1395+ return config_;
1396+}
1397+
1398+void H264Encoder::SendIDRFrame() {
1399+ if (!encoder_)
1400+ return;
1401+
1402+ MCS_DEBUG("");
1403+
1404+ media_codec_source_request_idr_frame(encoder_);
1405+}
1406+
1407+} // namespace android
1408+} // namespace mcs
1409
1410=== added file 'src/mcs/android/h264encoder.h'
1411--- src/mcs/android/h264encoder.h 1970-01-01 00:00:00 +0000
1412+++ src/mcs/android/h264encoder.h 2016-02-25 12:47:02 +0000
1413@@ -0,0 +1,96 @@
1414+/*
1415+ * Copyright (C) 2016 Canonical, Ltd.
1416+ *
1417+ * This program is free software: you can redistribute it and/or modify it
1418+ * under the terms of the GNU General Public License version 3, as published
1419+ * by the Free Software Foundation.
1420+ *
1421+ * This program is distributed in the hope that it will be useful, but
1422+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1423+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1424+ * PURPOSE. See the GNU General Public License for more details.
1425+ *
1426+ * You should have received a copy of the GNU General Public License along
1427+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1428+ *
1429+ */
1430+
1431+#ifndef MCS_ANDORID_ENCODER_H_
1432+#define MCS_ANDORID_ENCODER_H_
1433+
1434+#include <memory>
1435+#include <thread>
1436+
1437+#include <hybris/media/media_codec_source_layer.h>
1438+
1439+#include "mcs/non_copyable.h"
1440+#include "mcs/utils.h"
1441+
1442+#include "mcs/video/baseencoder.h"
1443+#include "mcs/video/bufferqueue.h"
1444+
1445+namespace mcs {
1446+namespace android {
1447+class H264Encoder : public video::BaseEncoder {
1448+public:
1449+ typedef std::shared_ptr<H264Encoder> Ptr;
1450+
1451+ static BaseEncoder::Config DefaultConfiguration();
1452+
1453+ static Ptr Create();
1454+
1455+ ~H264Encoder();
1456+
1457+ bool IsValid() const override;
1458+
1459+ bool Configure(const BaseEncoder::Config &config);
1460+
1461+ void Start() override;
1462+ void Stop() override;
1463+
1464+ void QueueBuffer(const mcs::video::Buffer::Ptr &buffer);
1465+
1466+ void* NativeWindowHandle() const override;
1467+ BaseEncoder::Config Configuration() const override;
1468+
1469+ void SendIDRFrame() override;
1470+
1471+private:
1472+ H264Encoder();
1473+
1474+ void WorkerThread();
1475+
1476+ bool DoesBufferContainCodecConfig(MediaBufferWrapper *buffer);
1477+
1478+ MediaBufferWrapper* PackBuffer(const mcs::video::Buffer::Ptr &input_buffer, const mcs::TimestampUs &timestamp);
1479+
1480+private:
1481+ static int OnSourceStart(MediaMetaDataWrapper *meta, void *user_data);
1482+ static int OnSourceStop(void *user_data);
1483+ static int OnSourceRead(MediaBufferWrapper **buffer, void *user_data);
1484+ static int OnSourcePause(void *user_data);
1485+
1486+ static void OnBufferReturned(MediaBufferWrapper *buffer, void *user_data);
1487+
1488+private:
1489+ struct BufferItem {
1490+ mcs::video::Buffer::Ptr buffer;
1491+ MediaBufferWrapper *media_buffer;
1492+ };
1493+
1494+private:
1495+ BaseEncoder::Config config_;
1496+ MediaMessageWrapper *format_;
1497+ MediaSourceWrapper *source_;
1498+ MediaCodecSourceWrapper *encoder_;
1499+ bool running_;
1500+ std::thread worker_thread_;
1501+ mcs::video::BufferQueue::Ptr input_queue_;
1502+ std::vector<BufferItem> pending_buffers_;
1503+ mcs::TimestampUs start_time_;
1504+ uint32_t frame_count_;
1505+};
1506+} // namespace android
1507+} // namespace mcs
1508+
1509+#endif
1510
1511=== modified file 'src/mcs/basesourcemediamanager.cpp'
1512--- src/mcs/basesourcemediamanager.cpp 2015-12-07 16:02:43 +0000
1513+++ src/mcs/basesourcemediamanager.cpp 2016-02-25 12:47:02 +0000
1514@@ -15,12 +15,23 @@
1515 *
1516 */
1517
1518+#include <iostream>
1519+
1520 #include <glib.h>
1521
1522-#include "basesourcemediamanager.h"
1523-#include "logger.h"
1524+#include "mcs/logger.h"
1525+#include "mcs/basesourcemediamanager.h"
1526+#include "mcs/video/videoformat.h"
1527+
1528+namespace {
1529+static unsigned int next_session_id = 0;
1530+}
1531
1532 namespace mcs {
1533+BaseSourceMediaManager::BaseSourceMediaManager() :
1534+ session_id_(++next_session_id) {
1535+}
1536+
1537 wds::SessionType BaseSourceMediaManager::GetSessionType() const {
1538 return wds::VideoSession;
1539 }
1540@@ -38,24 +49,29 @@
1541 return sink_port1_;
1542 }
1543
1544-std::vector<wds::H264VideoCodec> GetH264VideoCodecs() {
1545+std::vector<wds::H264VideoCodec> BaseSourceMediaManager::GetH264VideoCodecs() {
1546 static std::vector<wds::H264VideoCodec> codecs;
1547 if (codecs.empty()) {
1548 wds::RateAndResolutionsBitmap cea_rr;
1549 wds::RateAndResolutionsBitmap vesa_rr;
1550 wds::RateAndResolutionsBitmap hh_rr;
1551- wds::RateAndResolution i;
1552- // declare that we support all resolutions, CHP and level 4.2
1553- // gstreamer should handle all of it :)
1554- for (i = wds::CEA640x480p60; i <= wds::CEA1920x1080p24; ++i)
1555- cea_rr.set(i);
1556- for (i = wds::VESA800x600p30; i <= wds::VESA1920x1200p30; ++i)
1557- vesa_rr.set(i);
1558- for (i = wds::HH800x480p30; i <= wds::HH848x480p60; ++i)
1559- hh_rr.set(i);
1560-
1561- wds::H264VideoCodec codec(wds::CHP, wds::k4_2, cea_rr, vesa_rr, hh_rr);
1562- codecs.push_back(codec);
1563+
1564+ // We only support 720p here for now as that is our best performing
1565+ // resolution with regard of all other bits in the pipeline. Eventually
1566+ // we will add 60 Hz here too but for now only everything up to 30 Hz.
1567+ cea_rr.set(wds::CEA1280x720p30);
1568+ cea_rr.set(wds::CEA1280x720p25);
1569+ cea_rr.set(wds::CEA1280x720p24);
1570+
1571+ // FIXME which profiles and formats we support highly depends on what
1572+ // android supports. But for now we just consider CBP with level 3.1
1573+ // as that is the same Android configures its setup with.
1574+ wds::H264VideoCodec codec1(wds::CBP, wds::k3_1, cea_rr, vesa_rr, hh_rr);
1575+ codecs.push_back(codec1);
1576+
1577+ DEBUG("Video codecs supported by us:");
1578+ for (auto c : codecs)
1579+ mcs::video::DumpVideoCodec(c);
1580 }
1581
1582 return codecs;
1583@@ -64,19 +80,32 @@
1584 bool BaseSourceMediaManager::InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,
1585 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) {
1586
1587+ DEBUG("Sink native resolution:");
1588+ mcs::video::DumpNativeFormat(sink_native_format);
1589+
1590+ DEBUG("Sink supports the following codecs:");
1591+ for (auto sink_codec : sink_supported_codecs) {
1592+ mcs::video::DumpVideoCodec(sink_codec);
1593+ }
1594+
1595+ bool success = false;
1596+
1597 format_ = wds::FindOptimalVideoFormat(sink_native_format,
1598 GetH264VideoCodecs(),
1599- sink_supported_codecs);
1600-
1601- INFO("Found optimal video format");
1602- INFO(" profile: %d", format_.profile);
1603- INFO(" level: %d", format_.level);
1604- INFO(" res type %d", format_.type);
1605- INFO(" rate & resolution %d", format_.rate_resolution);
1606-
1607- Configure();
1608-
1609- return true;
1610+ sink_supported_codecs,
1611+ &success);
1612+
1613+ // Workaround buggy wds code ..
1614+ if (format_.rate_resolution == wds::CEA1280x720p60)
1615+ format_.rate_resolution = wds::CEA1280x720p30;
1616+
1617+ if (!success)
1618+ MCS_WARNING("Failed to select proper video format");
1619+
1620+ DEBUG("Found optimal video format:");
1621+ mcs::video::DumpVideoFormat(format_);
1622+
1623+ return Configure();
1624 }
1625
1626 wds::H264VideoFormat BaseSourceMediaManager::GetOptimalVideoFormat() const {
1627@@ -102,4 +131,8 @@
1628 void BaseSourceMediaManager::SendIDRPicture() {
1629 WARNING("Unimplemented IDR picture request");
1630 }
1631+
1632+std::string BaseSourceMediaManager::GetSessionId() const {
1633+ return mcs::Utils::Sprintf("%d", session_id_);
1634+}
1635 } // namespace mcs
1636
1637=== modified file 'src/mcs/basesourcemediamanager.h'
1638--- src/mcs/basesourcemediamanager.h 2015-11-26 16:48:53 +0000
1639+++ src/mcs/basesourcemediamanager.h 2016-02-25 12:47:02 +0000
1640@@ -24,9 +24,11 @@
1641 class BaseSourceMediaManager : public wds::SourceMediaManager
1642 {
1643 public:
1644+ explicit BaseSourceMediaManager();
1645+
1646 void SetSinkRtpPorts(int port1, int port2) override;
1647 std::pair<int,int> GetSinkRtpPorts() const override;
1648- int GetLocalRtpPort() const override;
1649+ virtual int GetLocalRtpPort() const override;
1650 wds::SessionType GetSessionType() const override;
1651
1652 bool InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,
1653@@ -34,15 +36,18 @@
1654 wds::H264VideoFormat GetOptimalVideoFormat() const override;
1655 bool InitOptimalAudioFormat(const std::vector<wds::AudioCodec>& sink_supported_codecs) override;
1656 wds::AudioCodec GetOptimalAudioFormat() const override;
1657- void SendIDRPicture() override;
1658+ virtual void SendIDRPicture() override;
1659+ std::string GetSessionId() const override;
1660
1661 protected:
1662- virtual void Configure() = 0;
1663+ virtual bool Configure() = 0;
1664+ virtual std::vector<wds::H264VideoCodec> GetH264VideoCodecs();
1665
1666 protected:
1667 int sink_port1_;
1668 int sink_port2_;
1669 wds::H264VideoFormat format_;
1670+ unsigned int session_id_;
1671 };
1672 } // namespace mcs
1673 #endif
1674
1675=== added file 'src/mcs/config.h.in'
1676--- src/mcs/config.h.in 1970-01-01 00:00:00 +0000
1677+++ src/mcs/config.h.in 2016-02-25 12:47:02 +0000
1678@@ -0,0 +1,25 @@
1679+/*
1680+ * Copyright (C) 2015 Canonical, Ltd.
1681+ *
1682+ * This program is free software: you can redistribute it and/or modify it
1683+ * under the terms of the GNU General Public License version 3, as published
1684+ * by the Free Software Foundation.
1685+ *
1686+ * This program is distributed in the hope that it will be useful, but
1687+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1688+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1689+ * PURPOSE. See the GNU General Public License for more details.
1690+ *
1691+ * You should have received a copy of the GNU General Public License along
1692+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1693+ *
1694+ */
1695+
1696+#ifndef MCS_CONFIG_H_
1697+#define MCS_CONFIG_H_
1698+
1699+namespace mcs {
1700+constexpr const char* kRuntimePath{"/run/aethercast"};
1701+}
1702+
1703+#endif
1704
1705=== removed file 'src/mcs/config.h.in'
1706--- src/mcs/config.h.in 2016-01-19 21:50:49 +0000
1707+++ src/mcs/config.h.in 1970-01-01 00:00:00 +0000
1708@@ -1,25 +0,0 @@
1709-/*
1710- * Copyright (C) 2015 Canonical, Ltd.
1711- *
1712- * This program is free software: you can redistribute it and/or modify it
1713- * under the terms of the GNU General Public License version 3, as published
1714- * by the Free Software Foundation.
1715- *
1716- * This program is distributed in the hope that it will be useful, but
1717- * WITHOUT ANY WARRANTY; without even the implied warranties of
1718- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1719- * PURPOSE. See the GNU General Public License for more details.
1720- *
1721- * You should have received a copy of the GNU General Public License along
1722- * with this program. If not, see <http://www.gnu.org/licenses/>.
1723- *
1724- */
1725-
1726-#ifndef MCS_CONFIG_H_
1727-#define MCS_CONFIG_H_
1728-
1729-namespace mcs {
1730-constexpr const char* kRuntimePath{"/run/aethercast"};
1731-}
1732-
1733-#endif
1734
1735=== modified file 'src/mcs/forwardingmiracastcontroller.cpp'
1736--- src/mcs/forwardingmiracastcontroller.cpp 2016-01-21 13:25:31 +0000
1737+++ src/mcs/forwardingmiracastcontroller.cpp 2016-02-25 12:47:02 +0000
1738@@ -42,8 +42,12 @@
1739 fwd_->Disconnect(device, callback);
1740 }
1741
1742-void ForwardingMiracastController::Scan(const std::chrono::seconds &timeout) {
1743- fwd_->Scan(timeout);
1744+void ForwardingMiracastController::DisconnectAll(ResultCallback callback) {
1745+ fwd_->DisconnectAll(callback);
1746+}
1747+
1748+mcs::Error ForwardingMiracastController::Scan(const std::chrono::seconds &timeout) {
1749+ return fwd_->Scan(timeout);
1750 }
1751
1752 NetworkDeviceState ForwardingMiracastController::State() const {
1753
1754=== modified file 'src/mcs/forwardingmiracastcontroller.h'
1755--- src/mcs/forwardingmiracastcontroller.h 2016-01-21 13:25:31 +0000
1756+++ src/mcs/forwardingmiracastcontroller.h 2016-02-25 12:47:02 +0000
1757@@ -32,7 +32,9 @@
1758 virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) override;
1759 virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) override;
1760
1761- virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;
1762+ virtual void DisconnectAll(ResultCallback callback) override;
1763+
1764+ virtual mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;
1765
1766 virtual NetworkDeviceState State() const override;
1767 virtual std::vector<NetworkManager::Capability> Capabilities() const override;
1768
1769=== removed file 'src/mcs/forwardingnetworkdevice.cpp'
1770--- src/mcs/forwardingnetworkdevice.cpp 2015-12-16 08:04:35 +0000
1771+++ src/mcs/forwardingnetworkdevice.cpp 1970-01-01 00:00:00 +0000
1772@@ -1,51 +0,0 @@
1773-/*
1774-* Copyright (C) 2015 Canonical, Ltd.
1775-*
1776-* This program is free software: you can redistribute it and/or modify it
1777-* under the terms of the GNU General Public License version 3, as published
1778-* by the Free Software Foundation.
1779-*
1780-* This program is distributed in the hope that it will be useful, but
1781-* WITHOUT ANY WARRANTY; without even the implied warranties of
1782-* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1783-* PURPOSE. See the GNU General Public License for more details.
1784-*
1785-* You should have received a copy of the GNU General Public License along
1786-* with this program. If not, see <http://www.gnu.org/licenses/>.
1787-*
1788-*/
1789-
1790-#include "forwardingnetworkdevice.h"
1791-
1792-namespace mcs {
1793-
1794-ForwardingNetworkDevice::ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd) : fwd_(fwd) {
1795- if (not fwd_) {
1796- throw std::logic_error{"Cannot operate without a valid NetworkDevice instance."};
1797- }
1798-}
1799-
1800-MacAddress ForwardingNetworkDevice::Address() const {
1801- return fwd_->Address();
1802-}
1803-
1804-IpV4Address ForwardingNetworkDevice::IPv4Address() const {
1805- return fwd_->IPv4Address();
1806-}
1807-
1808-std::string ForwardingNetworkDevice::Name() const {
1809- return fwd_->Name();
1810-}
1811-
1812-NetworkDeviceState ForwardingNetworkDevice::State() const {
1813- return fwd_->State();
1814-}
1815-
1816-std::vector<NetworkDeviceRole> ForwardingNetworkDevice::SupportedRoles() const {
1817- return fwd_->SupportedRoles();
1818-}
1819-
1820-const NetworkDevice::Ptr& ForwardingNetworkDevice::Fwd() const {
1821- return fwd_;
1822-}
1823-} // namespace mcs
1824
1825=== added file 'src/mcs/forwardingnetworkdevice.h'
1826--- src/mcs/forwardingnetworkdevice.h 1970-01-01 00:00:00 +0000
1827+++ src/mcs/forwardingnetworkdevice.h 2016-02-25 12:47:02 +0000
1828@@ -0,0 +1,42 @@
1829+/*
1830+* Copyright (C) 2015 Canonical, Ltd.
1831+*
1832+* This program is free software: you can redistribute it and/or modify it
1833+* under the terms of the GNU General Public License version 3, as published
1834+* by the Free Software Foundation.
1835+*
1836+* This program is distributed in the hope that it will be useful, but
1837+* WITHOUT ANY WARRANTY; without even the implied warranties of
1838+* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1839+* PURPOSE. See the GNU General Public License for more details.
1840+*
1841+* You should have received a copy of the GNU General Public License along
1842+* with this program. If not, see <http://www.gnu.org/licenses/>.
1843+*
1844+*/
1845+
1846+#ifndef FORWARDINGNETWORKDEVICE_H_
1847+#define FORWARDINGNETWORKDEVICE_H_
1848+
1849+#include "networkdevice.h"
1850+
1851+namespace mcs {
1852+
1853+class ForwardingNetworkDevice : public NetworkDevice {
1854+public:
1855+ ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd);
1856+
1857+ MacAddress Address() const override;
1858+ IpV4Address IPv4Address() const override;
1859+ std::string Name() const override;
1860+ NetworkDeviceState State() const override;
1861+ std::vector<NetworkDeviceRole> SupportedRoles() const override;
1862+
1863+protected:
1864+ const NetworkDevice::Ptr& Fwd() const;
1865+
1866+private:
1867+ NetworkDevice::Ptr fwd_;
1868+};
1869+} // namespace mcs
1870+#endif
1871
1872=== removed file 'src/mcs/forwardingnetworkdevice.h'
1873--- src/mcs/forwardingnetworkdevice.h 2015-12-16 08:04:35 +0000
1874+++ src/mcs/forwardingnetworkdevice.h 1970-01-01 00:00:00 +0000
1875@@ -1,42 +0,0 @@
1876-/*
1877-* Copyright (C) 2015 Canonical, Ltd.
1878-*
1879-* This program is free software: you can redistribute it and/or modify it
1880-* under the terms of the GNU General Public License version 3, as published
1881-* by the Free Software Foundation.
1882-*
1883-* This program is distributed in the hope that it will be useful, but
1884-* WITHOUT ANY WARRANTY; without even the implied warranties of
1885-* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1886-* PURPOSE. See the GNU General Public License for more details.
1887-*
1888-* You should have received a copy of the GNU General Public License along
1889-* with this program. If not, see <http://www.gnu.org/licenses/>.
1890-*
1891-*/
1892-
1893-#ifndef FORWARDINGNETWORKDEVICE_H_
1894-#define FORWARDINGNETWORKDEVICE_H_
1895-
1896-#include "networkdevice.h"
1897-
1898-namespace mcs {
1899-
1900-class ForwardingNetworkDevice : public NetworkDevice {
1901-public:
1902- ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd);
1903-
1904- MacAddress Address() const override;
1905- IpV4Address IPv4Address() const override;
1906- std::string Name() const override;
1907- NetworkDeviceState State() const override;
1908- std::vector<NetworkDeviceRole> SupportedRoles() const override;
1909-
1910-protected:
1911- const NetworkDevice::Ptr& Fwd() const;
1912-
1913-private:
1914- NetworkDevice::Ptr fwd_;
1915-};
1916-} // namespace mcs
1917-#endif
1918
1919=== modified file 'src/mcs/gstsourcemediamanager.cpp'
1920--- src/mcs/gstsourcemediamanager.cpp 2015-12-09 16:07:13 +0000
1921+++ src/mcs/gstsourcemediamanager.cpp 2016-02-25 12:47:02 +0000
1922@@ -60,48 +60,65 @@
1923 g_free (debug);
1924 break;
1925 default:
1926- /* unhandled message */
1927+ DEBUG("");
1928 break;
1929 }
1930
1931 return TRUE;
1932 }
1933
1934-void GstSourceMediaManager::Configure() {
1935+bool GstSourceMediaManager::Configure() {
1936+ DEBUG("");
1937+
1938 pipeline_ = ConstructPipeline(format_);
1939+ if (!pipeline_)
1940+ return false;
1941
1942 ScopedGObject<GstBus> bus{gst_pipeline_get_bus (GST_PIPELINE(pipeline_.get()))};
1943 bus_watch_id_ = gst_bus_add_watch(bus.get(), &GstSourceMediaManager::OnGstBusEvent, nullptr);
1944
1945 // Prepare pipeline so we're ready to go as soon as needed
1946 gst_element_set_state(pipeline_.get(), GST_STATE_READY);
1947+
1948+ return true;
1949 }
1950
1951 void GstSourceMediaManager::Play() {
1952 if (!pipeline_)
1953 return;
1954
1955+ DEBUG("");
1956+
1957 gst_element_set_state(pipeline_.get(), GST_STATE_PLAYING);
1958+ gst_element_get_state(pipeline_.get(), nullptr, nullptr, GST_CLOCK_TIME_NONE);
1959 }
1960
1961 void GstSourceMediaManager::Pause() {
1962 if (!pipeline_)
1963 return;
1964
1965+ DEBUG("");
1966+
1967 gst_element_set_state(pipeline_.get(), GST_STATE_PAUSED);
1968+ gst_element_get_state(pipeline_.get(), nullptr, nullptr, GST_CLOCK_TIME_NONE);
1969 }
1970
1971 void GstSourceMediaManager::Teardown() {
1972 if (!pipeline_)
1973 return;
1974
1975+ DEBUG("");
1976+
1977 gst_element_set_state(pipeline_.get(), GST_STATE_READY);
1978+ gst_element_get_state(pipeline_.get(), nullptr, nullptr, GST_CLOCK_TIME_NONE);
1979 }
1980
1981 bool GstSourceMediaManager::IsPaused() const {
1982 if (!pipeline_)
1983 return true;
1984
1985+ DEBUG("");
1986+
1987 GstState state;
1988 gst_element_get_state(pipeline_.get(), &state, nullptr, GST_CLOCK_TIME_NONE);
1989
1990
1991=== modified file 'src/mcs/gstsourcemediamanager.h'
1992--- src/mcs/gstsourcemediamanager.h 2015-11-30 16:16:49 +0000
1993+++ src/mcs/gstsourcemediamanager.h 2016-02-25 12:47:02 +0000
1994@@ -29,7 +29,7 @@
1995 public BaseSourceMediaManager
1996 {
1997 public:
1998- ~GstSourceMediaManager();
1999+ virtual ~GstSourceMediaManager();
2000
2001 void Play() override;
2002 void Pause() override;
2003@@ -38,7 +38,7 @@
2004
2005 protected:
2006 GstSourceMediaManager();
2007- void Configure() override;
2008+ bool Configure() override;
2009
2010 virtual SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) = 0;
2011
2012
2013=== added file 'src/mcs/initgstreameronce.cpp'
2014--- src/mcs/initgstreameronce.cpp 1970-01-01 00:00:00 +0000
2015+++ src/mcs/initgstreameronce.cpp 2016-02-25 12:47:02 +0000
2016@@ -0,0 +1,88 @@
2017+/*
2018+ * Copyright (C) 2015 Canonical, Ltd.
2019+ *
2020+ * This program is free software: you can redistribute it and/or modify it
2021+ * under the terms of the GNU General Public License version 3, as published
2022+ * by the Free Software Foundation.
2023+ *
2024+ * This program is distributed in the hope that it will be useful, but
2025+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2026+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2027+ * PURPOSE. See the GNU General Public License for more details.
2028+ *
2029+ * You should have received a copy of the GNU General Public License along
2030+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2031+ *
2032+ */
2033+
2034+#include <atomic>
2035+
2036+#include <gst/gst.h>
2037+
2038+#include "initgstreameronce.h"
2039+#include "logger.h"
2040+
2041+namespace {
2042+void GstLog (GstDebugCategory *category,
2043+ GstDebugLevel level,
2044+ const gchar *file,
2045+ const gchar *function,
2046+ gint line,
2047+ GObject *object,
2048+ GstDebugMessage *message,
2049+ gpointer user_data) {
2050+
2051+ boost::optional<mcs::Logger::Location> location;
2052+ if (file && function && line > 0) {
2053+ location = mcs::Logger::Location{file, function, line};
2054+ }
2055+
2056+ mcs::Log().Log(mcs::GstDebugLevelToSeverity(level), gst_debug_message_get(message), location);
2057+}
2058+}
2059+namespace mcs {
2060+Logger::Severity GstDebugLevelToSeverity(GstDebugLevel level) {
2061+ switch (level) {
2062+ case GST_LEVEL_NONE:
2063+ case GST_LEVEL_ERROR:
2064+ return Logger::Severity::kError;
2065+ case GST_LEVEL_WARNING:
2066+ case GST_LEVEL_FIXME:
2067+ return Logger::Severity::kWarning;
2068+ case GST_LEVEL_INFO:
2069+ return Logger::Severity::kInfo;
2070+ case GST_LEVEL_DEBUG:
2071+ return Logger::Severity::kDebug;
2072+ case GST_LEVEL_LOG:
2073+ return Logger::Severity::kDebug;
2074+ case GST_LEVEL_TRACE:
2075+ case GST_LEVEL_MEMDUMP:
2076+ return Logger::Severity::kTrace;
2077+ default:
2078+ return Logger::Severity::kInfo;
2079+ }
2080+}
2081+
2082+void InitGstreamerOnceOrThrow() {
2083+ static std::atomic<bool> initialized(false);
2084+ if (initialized.exchange(true))
2085+ return;
2086+
2087+ GError* error = nullptr;
2088+ if (gst_init_check(nullptr, nullptr, &error) == FALSE) {
2089+ auto what = Utils::Sprintf("Failed to initialize gstreamer (%s: %s)", g_quark_to_string(error->domain), error->message);
2090+ g_error_free(error);
2091+ throw std::runtime_error{what};
2092+ }
2093+
2094+ // Get rid of gstreamer's default log function.
2095+ gst_debug_remove_log_function(nullptr);
2096+ // And install our own.
2097+ gst_debug_add_log_function(GstLog, nullptr, nullptr);
2098+ // No need to, our logging infra takes care of that, too.
2099+ gst_debug_set_colored(FALSE);
2100+ auto gst_debug = Utils::GetEnvValue("AETHERCAST_GST_DEBUG");
2101+ if (not gst_debug.empty())
2102+ gst_debug_set_threshold_from_string(gst_debug.c_str(), FALSE);
2103+}
2104+}
2105
2106=== added file 'src/mcs/initgstreameronce.h'
2107--- src/mcs/initgstreameronce.h 1970-01-01 00:00:00 +0000
2108+++ src/mcs/initgstreameronce.h 2016-02-25 12:47:02 +0000
2109@@ -0,0 +1,29 @@
2110+/*
2111+ * Copyright (C) 2015 Canonical, Ltd.
2112+ *
2113+ * This program is free software: you can redistribute it and/or modify it
2114+ * under the terms of the GNU General Public License version 3, as published
2115+ * by the Free Software Foundation.
2116+ *
2117+ * This program is distributed in the hope that it will be useful, but
2118+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2119+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2120+ * PURPOSE. See the GNU General Public License for more details.
2121+ *
2122+ * You should have received a copy of the GNU General Public License along
2123+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2124+ *
2125+ */
2126+
2127+#include <gst/gst.h>
2128+
2129+#include "logger.h"
2130+
2131+namespace mcs {
2132+// GstDebugLevelToSeverity maps a GstDebugLevel to a Logger::Severity;
2133+Logger::Severity GstDebugLevelToSeverity(GstDebugLevel);
2134+
2135+// InitGstreamerOnceOrThrow initializes GStreamer, redirecting
2136+// its debug output to the mcs::Logger facilities.
2137+void InitGstreamerOnceOrThrow();
2138+}
2139
2140=== modified file 'src/mcs/logger.cpp'
2141--- src/mcs/logger.cpp 2015-12-09 07:37:10 +0000
2142+++ src/mcs/logger.cpp 2016-02-25 12:47:02 +0000
2143@@ -15,6 +15,8 @@
2144 *
2145 */
2146
2147+#include <thread>
2148+
2149 #include "logger.h"
2150
2151 #define BOOST_LOG_DYN_LINK
2152@@ -34,7 +36,14 @@
2153 }
2154
2155 struct BoostLogLogger : public mcs::Logger {
2156- BoostLogLogger() {
2157+ BoostLogLogger() :
2158+ initialized_(false) {
2159+ }
2160+
2161+ void Init(const mcs::Logger::Severity &severity = mcs::Logger::Severity::kWarning) override {
2162+ if (initialized_)
2163+ return;
2164+
2165 boost::log::formatter formatter = boost::log::expressions::stream
2166 << "[" << attrs::Severity << " "
2167 << boost::log::expressions::format_date_time< boost::posix_time::ptime >("Timestamp", "%Y-%m-%d %H:%M:%S")
2168@@ -48,10 +57,16 @@
2169 boost::log::core::get()->remove_all_sinks();
2170 auto logger = boost::log::add_console_log(std::cout);
2171 logger->set_formatter(formatter);
2172- // logger->set_filter(attrs::Severity < mcs::Logger::Severity::kInfo);
2173+
2174+ // logger->set_filter(attrs::Severity < severity);
2175+
2176+ initialized_ = true;
2177 }
2178
2179 void Log(Severity severity, const std::string& message, const boost::optional<Location> &loc) {
2180+ if (!initialized_)
2181+ Init();
2182+
2183 if (auto rec = boost::log::trivial::logger::get().open_record()) {
2184 boost::log::record_ostream out{rec};
2185 out << boost::log::add_value(attrs::Severity, severity)
2186@@ -68,6 +83,9 @@
2187 boost::log::trivial::logger::get().push_record(std::move(rec));
2188 }
2189 }
2190+
2191+private:
2192+ bool initialized_;
2193 };
2194
2195 std::shared_ptr<mcs::Logger>& MutableInstance() {
2196
2197=== modified file 'src/mcs/logger.h'
2198--- src/mcs/logger.h 2015-12-09 07:31:06 +0000
2199+++ src/mcs/logger.h 2016-02-25 12:47:02 +0000
2200@@ -48,6 +48,8 @@
2201 std::uint32_t line; // The line in file that resulted in the log message.
2202 };
2203
2204+ virtual void Init(const mcs::Logger::Severity &severity = mcs::Logger::Severity::kWarning) = 0;
2205+
2206 virtual void Log(Severity severity, const std::string &message, const boost::optional<Location>& location) = 0;
2207
2208 virtual void Trace(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
2209@@ -57,6 +59,7 @@
2210 virtual void Error(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
2211 virtual void Fatal(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
2212
2213+
2214 template<typename... T>
2215 void Tracef(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
2216 Trace(Utils::Sprintf(pattern, std::forward<T>(args)...), location);
2217
2218=== modified file 'src/mcs/mediamanagerfactory.cpp'
2219--- src/mcs/mediamanagerfactory.cpp 2016-01-04 07:52:54 +0000
2220+++ src/mcs/mediamanagerfactory.cpp 2016-02-25 12:47:02 +0000
2221@@ -19,7 +19,7 @@
2222
2223 #include "logger.h"
2224 #include "mediamanagerfactory.h"
2225-#include "mirsourcemediamanager.h"
2226+#include "mir/sourcemediamanager.h"
2227 #include "x11sourcemediamanager.h"
2228 #include "testsourcemediamanager.h"
2229 #include "utils.h"
2230@@ -41,19 +41,23 @@
2231
2232 bool NullSourceMediaManager::IsPaused() const {
2233 WARNING("NullSourceMediaManager: Not implemented");
2234+ return false;
2235 }
2236
2237-void NullSourceMediaManager::Configure() {
2238+bool NullSourceMediaManager::Configure() {
2239 WARNING("NullSourceMediaManager: Not implemented");
2240+ return false;
2241 }
2242
2243 std::shared_ptr<BaseSourceMediaManager> MediaManagerFactory::CreateSource(const std::string &remote_address) {
2244 std::string type = Utils::GetEnvValue("MIRACAST_SOURCE_TYPE");
2245+ if (type.length() == 0)
2246+ type = "mir";
2247
2248 DEBUG("Creating source media manager of type %s", type.c_str());
2249
2250- if (type.length() == 0 || type == "mir")
2251- return std::make_shared<MirSourceMediaManager>(remote_address);
2252+ if (type == "mir")
2253+ return mcs::mir::SourceMediaManager::Create(remote_address);
2254 else if (type == "x11")
2255 return X11SourceMediaManager::create(remote_address);
2256 else if (type == "test")
2257
2258=== modified file 'src/mcs/mediamanagerfactory.h'
2259--- src/mcs/mediamanagerfactory.h 2015-12-02 15:13:13 +0000
2260+++ src/mcs/mediamanagerfactory.h 2016-02-25 12:47:02 +0000
2261@@ -33,7 +33,7 @@
2262 bool IsPaused() const override;
2263
2264 protected:
2265- void Configure() override;
2266+ bool Configure() override;
2267 };
2268
2269 class MediaManagerFactory {
2270
2271=== added directory 'src/mcs/mir'
2272=== added file 'src/mcs/mir/mediasender.cpp'
2273--- src/mcs/mir/mediasender.cpp 1970-01-01 00:00:00 +0000
2274+++ src/mcs/mir/mediasender.cpp 2016-02-25 12:47:02 +0000
2275@@ -0,0 +1,155 @@
2276+/*
2277+ * Copyright (C) 2015 Canonical, Ltd.
2278+ *
2279+ * This program is free software: you can redistribute it and/or modify it
2280+ * under the terms of the GNU General Public License version 3, as published
2281+ * by the Free Software Foundation.
2282+ *
2283+ * This program is distributed in the hope that it will be useful, but
2284+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2285+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2286+ * PURPOSE. See the GNU General Public License for more details.
2287+ *
2288+ * You should have received a copy of the GNU General Public License along
2289+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2290+ *
2291+ */
2292+
2293+#include <stdio.h>
2294+
2295+#include "mcs/logger.h"
2296+
2297+#include "mcs/video/statistics.h"
2298+
2299+#include "mcs/mir/mediasender.h"
2300+
2301+namespace {
2302+FILE *dump_file = nullptr;
2303+static constexpr const char *kMediaSenderThreadName{"MediaSender"};
2304+}
2305+
2306+namespace mcs {
2307+namespace mir {
2308+
2309+MediaSender::Ptr MediaSender::Create(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config) {
2310+ return std::shared_ptr<MediaSender>(new MediaSender(endpoint, config));
2311+}
2312+
2313+MediaSender::MediaSender(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config) :
2314+ prev_time_us_(-1ll),
2315+ queue_(video::BufferQueue::Create()),
2316+ running_(false) {
2317+
2318+ packetizer_ = streaming::MPEGTSPacketizer::Create();
2319+
2320+ // FIXME once we add support for audio this can be only used for video
2321+ // and we need to differentiate here per track.
2322+ streaming::MPEGTSPacketizer::TrackFormat format;
2323+ format.profile_idc = config.profile_idc;
2324+ format.level_idc = config.level_idc;
2325+ format.constraint_set = config.constraint_set;
2326+ format.mime = "video/avc";
2327+
2328+ video_track_ = packetizer_->AddTrack(format);
2329+
2330+ rtp_sender_ = streaming::RTPSender::Create();
2331+ rtp_sender_->Setup(endpoint.address, endpoint.port);
2332+
2333+ if (mcs::Utils::IsEnvSet("AETHERCAST_MPEGTS_DUMP"))
2334+ dump_file = ::fopen(mcs::Utils::GetEnvValue("AETHERCAST_MPEGTS_DUMP").c_str(), "w");
2335+}
2336+
2337+MediaSender::~MediaSender() {
2338+ if (dump_file)
2339+ ::fclose(dump_file);
2340+
2341+ Stop();
2342+}
2343+
2344+void MediaSender::Start() {
2345+ if (running_)
2346+ return;
2347+
2348+ running_ = true;
2349+ worker_thread_ = std::thread(&MediaSender::WorkerThread, this);
2350+ pthread_setname_np(worker_thread_.native_handle(), kMediaSenderThreadName);
2351+}
2352+
2353+void MediaSender::Stop() {
2354+ if (!running_)
2355+ return;
2356+
2357+ running_ = false;
2358+ worker_thread_.join();
2359+}
2360+
2361+void MediaSender::ProcessBuffer(const mcs::video::Buffer::Ptr &buffer) {
2362+ mcs::video::Buffer::Ptr packets;
2363+
2364+ static int64_t start_time_us = mcs::Utils::GetNowUs();
2365+ static unsigned int buffer_count = 0;
2366+
2367+ buffer_count++;
2368+ int64_t time_now_us = mcs::Utils::GetNowUs();
2369+ if (start_time_us + 1000000ll <= time_now_us) {
2370+ video::Statistics::Instance()->RecordSenderBufferPerSecond(buffer_count);
2371+ buffer_count = 0;
2372+ start_time_us = time_now_us;
2373+ }
2374+
2375+ // FIXME: By default we're expecting the encoder to insert SPS and PPS
2376+ // with each IDR frame but we need to handle also the case where the
2377+ // encoder is not capable of doing this.
2378+#if 0
2379+ int flags = streaming::MPEGTSPacketizer::kPrependSPSandPPStoIDRFrames;
2380+#else
2381+ int flags = 0;
2382+#endif
2383+
2384+ // Per spec we need to emit PAT/PMT and PCR updates atleast every 100ms
2385+ int64_t time_us = mcs::Utils::GetNowUs();
2386+ if (prev_time_us_ < 0ll || prev_time_us_ + 100000ll <= time_us) {
2387+ flags |= streaming::MPEGTSPacketizer::kEmitPATandPMT;
2388+ flags |= streaming::MPEGTSPacketizer::kEmitPCR;
2389+ prev_time_us_ = time_us;
2390+ }
2391+
2392+ if (!packetizer_->Packetize(video_track_, buffer, &packets, flags)) {
2393+ MCS_ERROR("MPEGTS packetizing failed");
2394+ return;
2395+ }
2396+
2397+ if (dump_file)
2398+ ::fwrite(packets->Data(), 1, packets->Length(), dump_file);
2399+
2400+ packets->SetTimestamp(buffer->Timestamp());
2401+ rtp_sender_->QueueTSPackets(packets);
2402+}
2403+
2404+void MediaSender::WorkerThread() {
2405+ while (running_) {
2406+ // This will wait for a short time and then return back
2407+ // so we can loop again and check if we have to exit or
2408+ // not.
2409+ if (!queue_->WaitToBeFilled())
2410+ continue;
2411+
2412+ auto buffer = queue_->Pop();
2413+ ProcessBuffer(buffer);
2414+ }
2415+}
2416+
2417+void MediaSender::OnBufferAvailable(const video::Buffer::Ptr &buffer) {
2418+ queue_->Push(buffer);
2419+}
2420+
2421+void MediaSender::OnBufferWithCodecConfig(const video::Buffer::Ptr &buffer) {
2422+ packetizer_->SubmitCSD(video_track_, buffer);
2423+}
2424+
2425+uint16_t MediaSender::LocalRTPPort() const {
2426+ return rtp_sender_->LocalPort();
2427+}
2428+
2429+} // namespace mir
2430+} // namespace mcs
2431
2432=== added file 'src/mcs/mir/mediasender.h'
2433--- src/mcs/mir/mediasender.h 1970-01-01 00:00:00 +0000
2434+++ src/mcs/mir/mediasender.h 2016-02-25 12:47:02 +0000
2435@@ -0,0 +1,75 @@
2436+/*
2437+ * Copyright (C) 2015 Canonical, Ltd.
2438+ *
2439+ * This program is free software: you can redistribute it and/or modify it
2440+ * under the terms of the GNU General Public License version 3, as published
2441+ * by the Free Software Foundation.
2442+ *
2443+ * This program is distributed in the hope that it will be useful, but
2444+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2445+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2446+ * PURPOSE. See the GNU General Public License for more details.
2447+ *
2448+ * You should have received a copy of the GNU General Public License along
2449+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2450+ *
2451+ */
2452+
2453+#ifndef MCS_MIR_MEDIASENDER_H_
2454+#define MCS_MIR_MEDIASENDER_H_
2455+
2456+#include <memory>
2457+#include <mutex>
2458+
2459+#include "mcs/video/baseencoder.h"
2460+#include "mcs/video/bufferqueue.h"
2461+
2462+#include "mcs/streaming/mpegtspacketizer.h"
2463+#include "mcs/streaming/rtpsender.h"
2464+
2465+namespace mcs {
2466+namespace mir {
2467+
2468+class MediaSender : public std::enable_shared_from_this<MediaSender>,
2469+ public mcs::video::BaseEncoder::Delegate {
2470+public:
2471+ typedef std::shared_ptr<MediaSender> Ptr;
2472+
2473+ struct Endpoint {
2474+ std::string address;
2475+ unsigned int port;
2476+ };
2477+
2478+ static Ptr Create(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config);
2479+
2480+ ~MediaSender();
2481+
2482+ void Start();
2483+ void Stop();
2484+
2485+ void OnBufferAvailable(const mcs::video::Buffer::Ptr &buffer) override;
2486+ void OnBufferWithCodecConfig(const mcs::video::Buffer::Ptr &buffer) override;
2487+
2488+ uint16_t LocalRTPPort() const;
2489+
2490+private:
2491+ MediaSender(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config);
2492+
2493+ void WorkerThread();
2494+
2495+ void ProcessBuffer(const mcs::video::Buffer::Ptr &buffer);
2496+
2497+private:
2498+ streaming::MPEGTSPacketizer::Ptr packetizer_;
2499+ streaming::RTPSender::Ptr rtp_sender_;
2500+ streaming::MPEGTSPacketizer::TrackId video_track_;
2501+ int64_t prev_time_us_;
2502+ std::thread worker_thread_;
2503+ mcs::video::BufferQueue::Ptr queue_;
2504+ bool running_;
2505+};
2506+
2507+} // namespace mir
2508+} // namespace mcs
2509+
2510+#endif
2511
2512=== renamed file 'src/mcs/mirsourcemediamanager.cpp' => 'src/mcs/mir/sourcemediamanager.cpp'
2513--- src/mcs/mirsourcemediamanager.cpp 2015-12-07 16:02:43 +0000
2514+++ src/mcs/mir/sourcemediamanager.cpp 2016-02-25 12:47:02 +0000
2515@@ -15,99 +15,136 @@
2516 *
2517 */
2518
2519-#include <sstream>
2520-
2521-#include "mirsourcemediamanager.h"
2522-#include "utils.h"
2523-#include "logger.h"
2524+#include "mcs/logger.h"
2525+
2526+#include "mcs/video/statistics.h"
2527+#include "mcs/video/videoformat.h"
2528+
2529+#include "mcs/mir/sourcemediamanager.h"
2530+
2531+#include "mcs/android/h264encoder.h"
2532
2533 namespace mcs {
2534-MirSourceMediaManager::MirSourceMediaManager(const std::string &remote_address) :
2535- remote_address_(remote_address) {
2536-}
2537-
2538-MirSourceMediaManager::~MirSourceMediaManager() {
2539-}
2540-
2541-SharedGObject<GstElement> MirSourceMediaManager::ConstructPipeline(const wds::H264VideoFormat &format) {
2542- int width = 0, height = 0;
2543- std::string profile = "constrained-baseline";
2544-
2545- switch (format.profile) {
2546- case wds::CBP:
2547- profile = "constrained-baseline";
2548- break;
2549- case wds::CHP:
2550- profile = "high";
2551- break;
2552- }
2553-
2554- switch (format.type) {
2555- case wds::CEA:
2556- switch (format.rate_resolution) {
2557- case wds::CEA640x480p60:
2558- width = 640;
2559- height = 480;
2560- break;
2561- case wds::CEA720x480p60:
2562- case wds::CEA720x480i60:
2563- width = 720;
2564- height = 480;
2565- break;
2566- case wds::CEA720x576p50:
2567- case wds::CEA720x576i50:
2568- width = 720;
2569- height = 576;
2570- break;
2571- case wds::CEA1280x720p30:
2572- case wds::CEA1280x720p60:
2573- width = 1280;
2574- height = 720;
2575- break;
2576- case wds::CEA1920x1080p30:
2577- case wds::CEA1920x1080p60:
2578- case wds::CEA1920x1080i60:
2579- width = 1920;
2580- height = 1080;
2581- break;
2582- case wds::CEA1280x720p25:
2583- case wds::CEA1280x720p50:
2584- case wds::CEA1280x720p24:
2585- width = 1280;
2586- height = 720;
2587- break;
2588- case wds::CEA1920x1080p25:
2589- case wds::CEA1920x1080p50:
2590- case wds::CEA1920x1080i50:
2591- case wds::CEA1920x1080p24:
2592- width = 1920;
2593- height = 1080;
2594- break;
2595- default:
2596- break;
2597- }
2598- break;
2599- default:
2600- break;
2601- }
2602-
2603- std::stringstream ss;
2604- ss << "mirimagesrc mir-socket=/run/mir_socket ! videoconvert ! videoscale ! ";
2605- ss << Utils::Sprintf("video/x-raw,width=%d,height=%d ! ", width, height);
2606- ss << "videoflip method=counterclockwise ! queue2 ! video/x-raw,format=I420 ! ";
2607- ss << "x264enc aud=false byte-stream=true tune=zerolatency ! ";
2608- ss << Utils::Sprintf("video/x-h264,profile=%s ! ", profile.c_str());
2609- ss << "mpegtsmux ! rtpmp2tpay ! ";
2610- ss << Utils::Sprintf("udpsink name=sink host=%s port=%d", remote_address_.c_str(), sink_port1_);
2611-
2612- GError *error = nullptr;
2613- GstElement *pipeline = gst_parse_launch(ss.str().c_str(), &error);
2614- if (error) {
2615- ERROR("Failed to setup GStreamer pipeline: %s", error->message);
2616- g_error_free(error);
2617- return nullptr;
2618- }
2619-
2620- return make_shared_gobject(pipeline);
2621-}
2622+namespace mir {
2623+
2624+SourceMediaManager::Ptr SourceMediaManager::Create(const std::string &remote_address) {
2625+ return std::shared_ptr<SourceMediaManager>(new SourceMediaManager(remote_address));
2626+}
2627+
2628+SourceMediaManager::SourceMediaManager(const std::string &remote_address) :
2629+ remote_address_(remote_address),
2630+ state_(State::Stopped) {
2631+}
2632+
2633+SourceMediaManager::~SourceMediaManager() {
2634+ if (state_ != State::Stopped)
2635+ StopPipeline();
2636+
2637+ mcs::video::Statistics::Instance()->Dump();
2638+}
2639+
2640+bool SourceMediaManager::Configure() {
2641+ auto rr = mcs::video::ExtractRateAndResolution(format_);
2642+
2643+ MCS_DEBUG("dimensions: %dx%d@%d", rr.width, rr.height, rr.framerate);
2644+
2645+ // FIXME we don't support any other mode than extend for now as that means some
2646+ // additional work from mir to still give us properly sized frames we can hand
2647+ // to the encoder.
2648+ StreamConnector::DisplayOutput output{StreamConnector::DisplayMode::kExtend, rr.width, rr.height};
2649+
2650+ connector_ = mcs::mir::StreamConnector::Create(output);
2651+ if (!connector_->IsValid())
2652+ return false;
2653+
2654+ encoder_ = mcs::android::H264Encoder::Create();
2655+
2656+ int profile = 0, level = 0, constraint = 0;
2657+ mcs::video::ExtractProfileLevel(format_, &profile, &level, &constraint);
2658+
2659+ auto config = mcs::android::H264Encoder::DefaultConfiguration();
2660+ config.width = rr.width;
2661+ config.height = rr.height;
2662+ config.framerate = rr.framerate;
2663+ config.profile_idc = profile;
2664+ config.level_idc = level;
2665+ config.constraint_set = constraint;
2666+
2667+ if (!encoder_->Configure(config))
2668+ return false;
2669+
2670+ encoder_->Start();
2671+
2672+ renderer_ = mcs::mir::StreamRenderer::Create(connector_, encoder_);
2673+ renderer_->SetDimensions(rr.width, rr.height);
2674+
2675+ sender_ = mcs::mir::MediaSender::Create(MediaSender::Endpoint{remote_address_, sink_port1_}, config);
2676+ encoder_->SetDelegate(sender_);
2677+
2678+ return true;
2679+}
2680+
2681+void SourceMediaManager::StartPipeline() {
2682+ sender_->Start();
2683+ encoder_->Start();
2684+ renderer_->StartThreaded();
2685+}
2686+
2687+void SourceMediaManager::StopPipeline() {
2688+ renderer_->Stop();
2689+ encoder_->Stop();
2690+ sender_->Stop();
2691+}
2692+
2693+void SourceMediaManager::Play() {
2694+ if (!IsPaused() || !renderer_)
2695+ return;
2696+
2697+ MCS_DEBUG("");
2698+
2699+ StartPipeline();
2700+
2701+ state_ = State::Playing;
2702+}
2703+
2704+void SourceMediaManager::Pause() {
2705+ if (IsPaused()|| !renderer_)
2706+ return;
2707+
2708+ MCS_DEBUG("");
2709+
2710+ StopPipeline();
2711+
2712+ state_ = State::Paused;
2713+}
2714+
2715+void SourceMediaManager::Teardown() {
2716+ if (state_ == State::Stopped || !renderer_)
2717+ return;
2718+
2719+ MCS_DEBUG("");
2720+
2721+ StopPipeline();
2722+
2723+ state_ = State::Stopped;
2724+}
2725+
2726+bool SourceMediaManager::IsPaused() const {
2727+ return state_ == State::Paused ||
2728+ state_ == State::Stopped;
2729+}
2730+
2731+void SourceMediaManager::SendIDRPicture() {
2732+ if (!encoder_)
2733+ return;
2734+
2735+ encoder_->SendIDRFrame();
2736+}
2737+
2738+int SourceMediaManager::GetLocalRtpPort() const {
2739+ MCS_DEBUG("local port %d", sender_->LocalRTPPort());
2740+ return sender_->LocalRTPPort();
2741+}
2742+
2743+} // namespace mir
2744 } // namespace mcs
2745
2746=== renamed file 'src/mcs/mirsourcemediamanager.h' => 'src/mcs/mir/sourcemediamanager.h'
2747--- src/mcs/mirsourcemediamanager.h 2015-11-30 10:41:56 +0000
2748+++ src/mcs/mir/sourcemediamanager.h 2016-02-25 12:47:02 +0000
2749@@ -15,22 +15,64 @@
2750 *
2751 */
2752
2753-#ifndef MIRMEDIAMANAGER_H_
2754-#define MIRMEDIAMANAGER_H_
2755-
2756-#include "gstsourcemediamanager.h"
2757+#ifndef MCS_MIR_SOURCEMEDIAMANAGERNEXT_H_
2758+#define MCS_MIR_SOURCEMEDIAMANAGERNEXT_H_
2759+
2760+#include <memory>
2761+
2762+#include "mcs/basesourcemediamanager.h"
2763+
2764+#include "mcs/video/baseencoder.h"
2765+
2766+#include "mcs/mir/streamconnector.h"
2767+#include "mcs/mir/streamrenderer.h"
2768+#include "mcs/mir/mediasender.h"
2769
2770 namespace mcs {
2771-class MirSourceMediaManager : public GstSourceMediaManager {
2772+namespace mir {
2773+
2774+class SourceMediaManager : public mcs::BaseSourceMediaManager {
2775 public:
2776- explicit MirSourceMediaManager(const std::string &remote_address);
2777- ~MirSourceMediaManager();
2778+ typedef std::shared_ptr<SourceMediaManager> Ptr;
2779+
2780+ enum class State {
2781+ Playing,
2782+ Paused,
2783+ Stopped
2784+ };
2785+
2786+ static Ptr Create(const std::string &remote_address);
2787+
2788+ ~SourceMediaManager();
2789+
2790+ void Play() override;
2791+ void Pause() override;
2792+ void Teardown() override;
2793+ bool IsPaused() const override;
2794+
2795+ void SendIDRPicture() override;
2796+
2797+ int GetLocalRtpPort() const override;
2798+
2799+private:
2800+ SourceMediaManager(const std::string &remote_address);
2801+
2802+ void StartPipeline();
2803+ void StopPipeline();
2804
2805 protected:
2806- SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) override;
2807+ bool Configure() override;
2808
2809 private:
2810 std::string remote_address_;
2811+ State state_;
2812+ mcs::video::BaseEncoder::Ptr encoder_;
2813+ mcs::mir::StreamConnector::Ptr connector_;
2814+ mcs::mir::StreamRenderer::Ptr renderer_;
2815+ mcs::mir::MediaSender::Ptr sender_;
2816 };
2817+
2818+} // namespace mir
2819 } // namespace mcs
2820+
2821 #endif
2822
2823=== added file 'src/mcs/mir/streamconnector.cpp'
2824--- src/mcs/mir/streamconnector.cpp 1970-01-01 00:00:00 +0000
2825+++ src/mcs/mir/streamconnector.cpp 2016-02-25 12:47:02 +0000
2826@@ -0,0 +1,204 @@
2827+/*
2828+ * Copyright (C) 2015 Canonical, Ltd.
2829+ *
2830+ * This program is free software: you can redistribute it and/or modify it
2831+ * under the terms of the GNU General Public License version 3, as published
2832+ * by the Free Software Foundation.
2833+ *
2834+ * This program is distributed in the hope that it will be useful, but
2835+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2836+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2837+ * PURPOSE. See the GNU General Public License for more details.
2838+ *
2839+ * You should have received a copy of the GNU General Public License along
2840+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2841+ *
2842+ */
2843+
2844+#include <boost/concept_check.hpp>
2845+
2846+#include "mcs/logger.h"
2847+#include "mcs/mir/streamconnector.h"
2848+
2849+namespace {
2850+static constexpr const char *kMirSocket{"/run/mir_socket"};
2851+static constexpr const char *kMirConnectionName{"aethercast screencast client"};
2852+}
2853+
2854+namespace mcs {
2855+namespace mir {
2856+
2857+std::string StreamConnector::DisplayModeToString(const DisplayMode &mode) {
2858+ switch (mode) {
2859+ case DisplayMode::kExtend:
2860+ return "extend";
2861+ case DisplayMode::kMirror:
2862+ return "mirror";
2863+ default:
2864+ break;
2865+ }
2866+ return "unknown";
2867+}
2868+
2869+StreamConnector::Ptr StreamConnector::Create(const StreamConnector::DisplayOutput &output) {
2870+ return std::shared_ptr<StreamConnector>(new StreamConnector(output));
2871+}
2872+
2873+StreamConnector::StreamConnector(const StreamConnector::DisplayOutput &output) :
2874+ output_(output) {
2875+ connection_ = mir_connect_sync(kMirSocket, kMirConnectionName);
2876+ if (!mir_connection_is_valid(connection_)) {
2877+ MCS_ERROR("Failed to connect to Mir server: %s",
2878+ mir_connection_get_error_message(connection_));
2879+ return;
2880+ }
2881+
2882+ auto config = mir_connection_create_display_config(connection_);
2883+
2884+ MirDisplayOutput *active_output = nullptr;
2885+ int output_index = 0;
2886+
2887+ for (unsigned int i = 0; i < config->num_outputs; ++i) {
2888+ if (config->outputs[i].connected &&
2889+ config->outputs[i].used &&
2890+ config->outputs[i].current_mode < config->outputs[i].num_modes) {
2891+ // Found an active connection we can just use for our purpose
2892+ active_output = &config->outputs[i];
2893+ output_index = i;
2894+ break;
2895+ }
2896+ }
2897+
2898+ if (!active_output) {
2899+ MCS_ERROR("Failed to find a suitable display output");
2900+ return;
2901+ }
2902+
2903+ const MirDisplayMode *display_mode = &active_output->modes[active_output->current_mode];
2904+
2905+ params_.height = display_mode->vertical_resolution;
2906+ params_.width = display_mode->horizontal_resolution;
2907+
2908+ if (output_.mode == DisplayMode::kMirror) {
2909+ params_.region.left = 0;
2910+ params_.region.top = 0;
2911+ params_.region.width = params_.width;
2912+ params_.region.height = params_.height;
2913+
2914+ output_.width = params_.width;
2915+ output_.height = params_.height;
2916+ }
2917+ else if (output_.mode == DisplayMode::kExtend) {
2918+ // If we request a screen region outside the available screen area
2919+ // mir will create a mir output which is then available for everyone
2920+ // as just another display.
2921+ params_.region.left = params_.width;
2922+ params_.region.top = 0;
2923+ params_.region.width = output_.width;
2924+ params_.region.height = output_.height;
2925+
2926+ params_.width = output_.width;
2927+ params_.height = output_.height;
2928+ }
2929+
2930+ output_.refresh_rate = display_mode->refresh_rate;
2931+
2932+ MCS_INFO("Selected output ID %i [(%ix%i)+(%ix%i)] orientation %d",
2933+ output_index,
2934+ params_.width, params_.height,
2935+ params_.region.left, params_.region.top,
2936+ active_output->orientation);
2937+
2938+ MCS_DEBUG("Setting up screencast [%s %dx%d]",
2939+ DisplayModeToString(output_.mode),
2940+ output_.width,
2941+ output_.height);
2942+
2943+ unsigned int num_pixel_formats = 0;
2944+ mir_connection_get_available_surface_formats(connection_, &params_.pixel_format,
2945+ 1, &num_pixel_formats);
2946+ if (num_pixel_formats == 0) {
2947+ MCS_ERROR("Failed to find suitable pixel format: %s",
2948+ mir_connection_get_error_message(connection_));
2949+ return;
2950+ }
2951+
2952+ screencast_ = mir_connection_create_screencast_sync(connection_, &params_);
2953+ if (!screencast_) {
2954+ MCS_ERROR("Failed to create Mir screencast: %s",
2955+ mir_connection_get_error_message(connection_));
2956+ return;
2957+ }
2958+
2959+ buffer_stream_ = mir_screencast_get_buffer_stream(screencast_);
2960+ if (!buffer_stream_) {
2961+ MCS_ERROR("Failed to setup Mir buffer stream");
2962+ return;
2963+ }
2964+
2965+ auto platform_type = mir_buffer_stream_get_platform_type(buffer_stream_);
2966+ if (platform_type != mir_platform_type_android) {
2967+ MCS_ERROR("Not running with android platform: This is not supported.");
2968+ mir_buffer_stream_release_sync(buffer_stream_);
2969+ buffer_stream_ = nullptr;
2970+ return;
2971+ }
2972+}
2973+
2974+StreamConnector::~StreamConnector() {
2975+ if (screencast_)
2976+ mir_screencast_release_sync(screencast_);
2977+
2978+ if (connection_)
2979+ mir_connection_release(connection_);
2980+}
2981+
2982+void StreamConnector::SwapBuffersSync() {
2983+ if (!buffer_stream_)
2984+ return;
2985+
2986+ mir_buffer_stream_swap_buffers_sync(buffer_stream_);
2987+}
2988+
2989+void StreamConnector::SwapBuffers() {
2990+ if (!buffer_stream_)
2991+ return;
2992+
2993+ mir_buffer_stream_swap_buffers(buffer_stream_, [](MirBufferStream *stream, void *client_context) {
2994+ boost::ignore_unused_variable_warning(stream);
2995+ boost::ignore_unused_variable_warning(client_context);
2996+
2997+ MCS_DEBUG("Buffers are swapped now");
2998+
2999+ }, nullptr);
3000+}
3001+
3002+bool StreamConnector::IsValid() const {
3003+ return connection_ && screencast_ && buffer_stream_;
3004+}
3005+
3006+void* StreamConnector::NativeWindowHandle() const {
3007+ if (!buffer_stream_)
3008+ return nullptr;
3009+
3010+ return reinterpret_cast<void*>(mir_buffer_stream_get_egl_native_window(buffer_stream_));
3011+}
3012+
3013+void* StreamConnector::NativeDisplayHandle() const {
3014+ if (!connection_)
3015+ return nullptr;
3016+
3017+ return mir_connection_get_egl_native_display(connection_);
3018+}
3019+
3020+StreamConnector::DisplayOutput StreamConnector::OutputMode() const {
3021+ return output_;
3022+}
3023+
3024+MirNativeBuffer* StreamConnector::CurrentBuffer() const {
3025+ MirNativeBuffer *buffer = nullptr;
3026+ mir_buffer_stream_get_current_buffer(buffer_stream_, &buffer);
3027+ return buffer;
3028+}
3029+} // namespace mir
3030+} // namespace mcs
3031
3032=== added file 'src/mcs/mir/streamconnector.h'
3033--- src/mcs/mir/streamconnector.h 1970-01-01 00:00:00 +0000
3034+++ src/mcs/mir/streamconnector.h 2016-02-25 12:47:02 +0000
3035@@ -0,0 +1,77 @@
3036+/*
3037+ * Copyright (C) 2015 Canonical, Ltd.
3038+ *
3039+ * This program is free software: you can redistribute it and/or modify it
3040+ * under the terms of the GNU General Public License version 3, as published
3041+ * by the Free Software Foundation.
3042+ *
3043+ * This program is distributed in the hope that it will be useful, but
3044+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3045+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3046+ * PURPOSE. See the GNU General Public License for more details.
3047+ *
3048+ * You should have received a copy of the GNU General Public License along
3049+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3050+ *
3051+ */
3052+
3053+#ifndef MCS_MIR_CONNECTOR_H_
3054+#define MCS_MIR_CONNECTOR_H_
3055+
3056+#include <memory>
3057+
3058+#include <mir_toolkit/mir_client_library.h>
3059+#include <mir_toolkit/mir_screencast.h>
3060+#include <mir_toolkit/mir_buffer_stream.h>
3061+
3062+namespace mcs {
3063+namespace mir {
3064+
3065+class StreamConnector {
3066+public:
3067+ typedef std::shared_ptr<StreamConnector> Ptr;
3068+
3069+ enum class DisplayMode {
3070+ kMirror,
3071+ kExtend
3072+ };
3073+
3074+ static std::string DisplayModeToString(const DisplayMode &mode);
3075+
3076+ struct DisplayOutput {
3077+ DisplayMode mode;
3078+ unsigned int width;
3079+ unsigned int height;
3080+ double refresh_rate;
3081+ };
3082+
3083+ static Ptr Create(const DisplayOutput &output);
3084+
3085+ ~StreamConnector();
3086+
3087+ void SwapBuffers();
3088+ void SwapBuffersSync();
3089+
3090+ bool IsValid() const;
3091+
3092+ void* NativeWindowHandle() const;
3093+ void* NativeDisplayHandle() const;
3094+
3095+ DisplayOutput OutputMode() const;
3096+ MirNativeBuffer* CurrentBuffer() const;
3097+
3098+private:
3099+ StreamConnector(const DisplayOutput &output);
3100+
3101+private:
3102+ MirConnection *connection_;
3103+ MirScreencast *screencast_;
3104+ MirBufferStream *buffer_stream_;
3105+ MirScreencastParameters params_;
3106+ DisplayOutput output_;
3107+};
3108+
3109+} // namespace mir
3110+} // namespace mcs
3111+
3112+#endif
3113
3114=== added file 'src/mcs/mir/streamrenderer.cpp'
3115--- src/mcs/mir/streamrenderer.cpp 1970-01-01 00:00:00 +0000
3116+++ src/mcs/mir/streamrenderer.cpp 2016-02-25 12:47:02 +0000
3117@@ -0,0 +1,175 @@
3118+/*
3119+ * Copyright (C) 2015 Canonical, Ltd.
3120+ *
3121+ * This program is free software: you can redistribute it and/or modify it
3122+ * under the terms of the GNU General Public License version 3, as published
3123+ * by the Free Software Foundation.
3124+ *
3125+ * This program is distributed in the hope that it will be useful, but
3126+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3127+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3128+ * PURPOSE. See the GNU General Public License for more details.
3129+ *
3130+ * You should have received a copy of the GNU General Public License along
3131+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3132+ *
3133+ */
3134+
3135+#define GL_GLEXT_PROTOTYPES
3136+#define EGL_EGLEXT_PROTOTYPES
3137+#include <EGL/egl.h>
3138+#include <EGL/eglext.h>
3139+#include <GLES2/gl2.h>
3140+#include <GLES2/gl2ext.h>
3141+
3142+#include <system/window.h>
3143+
3144+#include <chrono>
3145+#include <thread>
3146+
3147+#include <boost/concept_check.hpp>
3148+
3149+#include "mcs/logger.h"
3150+
3151+#include "mcs/video/statistics.h"
3152+
3153+#include "mcs/mir/streamconnector.h"
3154+#include "mcs/mir/streamrenderer.h"
3155+
3156+namespace {
3157+static constexpr const char *kStreamRendererThreadName{"StreamRenderer"};
3158+static constexpr unsigned int kNumBufferSlots{2};
3159+}
3160+
3161+namespace mcs {
3162+namespace mir {
3163+
3164+StreamRenderer::Ptr StreamRenderer::Create(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder) {
3165+ return std::shared_ptr<StreamRenderer>(new StreamRenderer(connector, encoder));
3166+}
3167+
3168+StreamRenderer::StreamRenderer(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder) :
3169+ connector_(connector),
3170+ encoder_(encoder),
3171+ running_(false),
3172+ width_(0),
3173+ height_(0),
3174+ input_buffers_(mcs::video::BufferQueue::Create(kNumBufferSlots)) {
3175+}
3176+
3177+StreamRenderer::~StreamRenderer() {
3178+ Stop();
3179+}
3180+
3181+void StreamRenderer::RenderThread() {
3182+ MCS_DEBUG("Everything successfully setup; Starting recording now %dx%d@%d",
3183+ width_, height_, encoder_->Configuration().framerate);
3184+
3185+ bool waiting = false;
3186+ mcs::TimestampUs wait_slot_time;
3187+
3188+ static int64_t start_time_us = mcs::Utils::GetNowUs();
3189+ static unsigned int frame_count = 0;
3190+ static const mcs::TimestampUs target_iteration_time = (1. / encoder_->Configuration().framerate) * 1000000ll;
3191+
3192+ while (running_) {
3193+ if (!waiting)
3194+ wait_slot_time = mcs::Utils::GetNowUs();
3195+
3196+ mcs::TimestampUs iteration_start_time = mcs::Utils::GetNowUs();
3197+
3198+ if (!input_buffers_->WaitForSlots()) {
3199+ waiting = true;
3200+ continue;
3201+ }
3202+
3203+ waiting = false;
3204+
3205+ int64_t wait_time = (mcs::Utils::GetNowUs() - wait_slot_time) / 1000ll;
3206+ video::Statistics::Instance()->RecordRendererWait(wait_time);
3207+
3208+ mcs::TimestampUs before_swap = mcs::Utils::GetNowUs();
3209+
3210+ // This will trigger the rendering/compositing process inside mir
3211+ // and will block until that is done and we received a new buffer
3212+ connector_->SwapBuffersSync();
3213+
3214+ int64_t swap_time = (mcs::Utils::GetNowUs() - before_swap) / 1000ll;
3215+ video::Statistics::Instance()->RecordRendererSwapped(swap_time);
3216+
3217+ auto native_buffer = connector_->CurrentBuffer();
3218+
3219+ auto buffer = mcs::video::Buffer::Create(native_buffer);
3220+ buffer->SetDelegate(shared_from_this());
3221+
3222+ frame_count++;
3223+ int64_t time_now_us = mcs::Utils::GetNowUs();
3224+ if (start_time_us + 1000000ll <= time_now_us) {
3225+ video::Statistics::Instance()->RecordRendererFramesPerSecond(frame_count);
3226+ frame_count = 0;
3227+ start_time_us = time_now_us;
3228+ }
3229+
3230+ // FIXME: at optimum we would get the timestamp directly supplied
3231+ // from mir but as long as that isn't available we don't have any
3232+ // other chance and need to do it here.
3233+ buffer->SetTimestamp(mcs::Utils::GetNowUs());
3234+
3235+ input_buffers_->Push(buffer);
3236+
3237+ encoder_->QueueBuffer(buffer);
3238+
3239+ static mcs::TimestampUs last_queued_time = mcs::Utils::GetNowUs();
3240+ int64_t renderer_iteration_time = (mcs::Utils::GetNowUs() - last_queued_time) / 1000ll;
3241+ last_queued_time = mcs::Utils::GetNowUs();
3242+ video::Statistics::Instance()->RecordRendererIteration(renderer_iteration_time);
3243+
3244+ mcs::TimestampUs iteration_time = mcs::Utils::GetNowUs() - iteration_start_time;
3245+ int64_t sleep_time = target_iteration_time - iteration_time;
3246+ if (sleep_time > 0)
3247+ std::this_thread::sleep_for(std::chrono::microseconds(sleep_time));
3248+ }
3249+}
3250+
3251+void StreamRenderer::OnBufferFinished(const video::Buffer::Ptr &buffer) {
3252+ boost::ignore_unused_variable_warning(buffer);
3253+
3254+ // We're currently relying on the buffers to come back in order so
3255+ // we can safely remove the head from the queue here which then
3256+ // gives us a free slot at the beginning which will be filled by
3257+ // the renderer again.
3258+ input_buffers_->Pop();
3259+}
3260+
3261+void StreamRenderer::SetDimensions(unsigned int width, unsigned int height) {
3262+ width_ = width;
3263+ height_ = height;
3264+}
3265+
3266+void StreamRenderer::StartThreaded() {
3267+ if (running_)
3268+ return;
3269+
3270+ auto output_mode = connector_->OutputMode();
3271+
3272+ if (width_ == 0 || height_ == 0) {
3273+ width_ = output_mode.width;
3274+ height_ = output_mode.height;
3275+ }
3276+
3277+ running_ = true;
3278+
3279+ render_thread_ = std::thread(&StreamRenderer::RenderThread, this);
3280+ pthread_setname_np(render_thread_.native_handle(), kStreamRendererThreadName);
3281+}
3282+
3283+void StreamRenderer::Stop() {
3284+ if (!running_)
3285+ return;
3286+
3287+ running_ = false;
3288+ render_thread_.join();
3289+}
3290+
3291+} // namespace mir
3292+} // namespace mcs
3293
3294=== added file 'src/mcs/mir/streamrenderer.h'
3295--- src/mcs/mir/streamrenderer.h 1970-01-01 00:00:00 +0000
3296+++ src/mcs/mir/streamrenderer.h 2016-02-25 12:47:02 +0000
3297@@ -0,0 +1,69 @@
3298+/*
3299+ * Copyright (C) 2016 Canonical, Ltd.
3300+ *
3301+ * This program is free software: you can redistribute it and/or modify it
3302+ * under the terms of the GNU General Public License version 3, as published
3303+ * by the Free Software Foundation.
3304+ *
3305+ * This program is distributed in the hope that it will be useful, but
3306+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3307+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3308+ * PURPOSE. See the GNU General Public License for more details.
3309+ *
3310+ * You should have received a copy of the GNU General Public License along
3311+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3312+ *
3313+ */
3314+
3315+#ifndef MCS_MIR_STREAMRENDERER_H_
3316+#define MCS_MIR_STREAMRENDERER_H_
3317+
3318+#include <memory>
3319+#include <thread>
3320+#include <mutex>
3321+#include <queue>
3322+
3323+#include "mcs/mir/streamrenderer.h"
3324+#include "mcs/mir/streamconnector.h"
3325+
3326+#include "mcs/video/baseencoder.h"
3327+#include "mcs/video/bufferqueue.h"
3328+
3329+namespace mcs {
3330+namespace mir {
3331+class StreamRenderer : public std::enable_shared_from_this<StreamRenderer>,
3332+ public mcs::video::Buffer::Delegate {
3333+public:
3334+ static constexpr unsigned int kNumTextures{2};
3335+
3336+ typedef std::shared_ptr<StreamRenderer> Ptr;
3337+
3338+ static Ptr Create(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder);
3339+
3340+ ~StreamRenderer();
3341+
3342+ void SetDimensions(unsigned int width, unsigned int height);
3343+
3344+ void StartThreaded();
3345+ void Stop();
3346+
3347+ void OnBufferFinished(const mcs::video::Buffer::Ptr &buffer);
3348+
3349+private:
3350+ StreamRenderer(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder);
3351+
3352+ void RenderThread();
3353+
3354+private:
3355+ StreamConnector::Ptr connector_;
3356+ video::BaseEncoder::Ptr encoder_;
3357+ std::thread render_thread_;
3358+ bool running_;
3359+ unsigned int width_;
3360+ unsigned int height_;
3361+ mcs::video::BufferQueue::Ptr input_buffers_;
3362+};
3363+} // namespace mir
3364+} // namespace mcs
3365+
3366+#endif
3367
3368=== modified file 'src/mcs/miracastcontroller.h'
3369--- src/mcs/miracastcontroller.h 2016-01-21 13:25:31 +0000
3370+++ src/mcs/miracastcontroller.h 2016-02-25 12:47:02 +0000
3371@@ -52,7 +52,9 @@
3372 virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;
3373 virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;
3374
3375- virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;
3376+ virtual void DisconnectAll(ResultCallback callback) = 0;
3377+
3378+ virtual mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;
3379
3380 virtual NetworkDeviceState State() const = 0;
3381 virtual std::vector<NetworkManager::Capability> Capabilities() const = 0;
3382
3383=== modified file 'src/mcs/miracastcontrollerskeleton.cpp'
3384--- src/mcs/miracastcontrollerskeleton.cpp 2016-01-21 13:25:31 +0000
3385+++ src/mcs/miracastcontrollerskeleton.cpp 2016-02-25 12:47:02 +0000
3386@@ -119,6 +119,10 @@
3387 G_CALLBACK(&MiracastControllerSkeleton::OnHandleScan), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
3388 [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
3389
3390+ g_signal_connect_data(inst->manager_obj_.get(), "handle-disconnect-all",
3391+ G_CALLBACK(&MiracastControllerSkeleton::OnHandleDisconnectAll), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
3392+ [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
3393+
3394 inst->SyncProperties();
3395
3396 g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(inst->manager_obj_.get()),
3397@@ -142,13 +146,43 @@
3398
3399 INFO("Scanning for remote devices");
3400
3401- inst->Scan();
3402+ auto error = inst->Scan();
3403+ if (error != mcs::Error::kNone) {
3404+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s", mcs::ErrorToString(error).c_str());
3405+ return TRUE;
3406+ }
3407
3408 g_dbus_method_invocation_return_value(invocation, nullptr);
3409
3410 return TRUE;
3411 }
3412
3413+gboolean MiracastControllerSkeleton::OnHandleDisconnectAll(AethercastInterfaceManager *skeleton,
3414+ GDBusMethodInvocation *invocation, gpointer user_data) {
3415+ boost::ignore_unused_variable_warning(skeleton);
3416+ auto inst = static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(user_data)->GetInstance().lock();
3417+
3418+ if (not inst) {
3419+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
3420+ return TRUE;
3421+ }
3422+
3423+ g_object_ref(invocation);
3424+ auto inv = make_shared_gobject(invocation);
3425+
3426+ inst->DisconnectAll([inv](mcs::Error error) {
3427+ if (error != Error::kNone) {
3428+ g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3429+ "%s", mcs::ErrorToString(error).c_str());
3430+ return;
3431+ }
3432+
3433+ g_dbus_method_invocation_return_value(inv.get(), nullptr);
3434+ });
3435+
3436+ return TRUE;
3437+}
3438+
3439 std::shared_ptr<MiracastControllerSkeleton> MiracastControllerSkeleton::FinalizeConstruction() {
3440 auto sp = shared_from_this();
3441
3442
3443=== modified file 'src/mcs/miracastcontrollerskeleton.h'
3444--- src/mcs/miracastcontrollerskeleton.h 2015-12-21 15:20:11 +0000
3445+++ src/mcs/miracastcontrollerskeleton.h 2016-02-25 12:47:02 +0000
3446@@ -58,6 +58,8 @@
3447
3448 static gboolean OnHandleScan(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
3449 gpointer user_data);
3450+ static gboolean OnHandleDisconnectAll(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
3451+ gpointer user_data);
3452
3453 MiracastControllerSkeleton(const std::shared_ptr<MiracastController> &controller);
3454 std::shared_ptr<MiracastControllerSkeleton> FinalizeConstruction();
3455
3456=== modified file 'src/mcs/miracastservice.cpp'
3457--- src/mcs/miracastservice.cpp 2016-01-21 13:25:31 +0000
3458+++ src/mcs/miracastservice.cpp 2016-02-25 12:47:02 +0000
3459@@ -20,6 +20,9 @@
3460 #include <cstdint>
3461
3462 #include <sys/prctl.h>
3463+#include <signal.h>
3464+#include <sys/time.h>
3465+#include <sys/resource.h>
3466
3467 #include <glib.h>
3468 #include <glib-unix.h>
3469@@ -31,6 +34,7 @@
3470
3471 #include <wds/logging.h>
3472
3473+#include "initgstreameronce.h"
3474 #include "config.h"
3475 #include "keep_alive.h"
3476 #include "logger.h"
3477@@ -45,6 +49,7 @@
3478 const std::uint16_t kMiracastDefaultRtspCtrlPort{7236};
3479 const std::chrono::milliseconds kStateIdleTimeout{5000};
3480 const std::chrono::seconds kShutdownGracePreriod{1};
3481+const std::int16_t kProcessPriorityUrgentDisplay{-8};
3482
3483 // SafeLog serves as integration point to the wds::LogSystem world.
3484 template <mcs::Logger::Severity severity>
3485@@ -94,6 +99,9 @@
3486 return 0;
3487 }
3488
3489+ if (options.debug)
3490+ mcs::Log().Init(mcs::Logger::Severity::kDebug);
3491+
3492 struct Runtime {
3493 static gboolean OnSignalRaised(gpointer user_data) {
3494 auto thiz = static_cast<Runtime*>(user_data);
3495@@ -122,6 +130,9 @@
3496 g_unix_signal_add(SIGINT, OnSignalRaised, this);
3497 g_unix_signal_add(SIGTERM, OnSignalRaised, this);
3498
3499+ // Initialize gstreamer.
3500+ mcs::InitGstreamerOnceOrThrow();
3501+
3502 // Redirect all wds logging to our own.
3503 wds::LogSystem::set_vlog_func(SafeLog<mcs::Logger::Severity::kTrace>);
3504 wds::LogSystem::set_log_func(SafeLog<mcs::Logger::Severity::kInfo>);
3505@@ -156,6 +167,9 @@
3506 if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
3507 g_warning("Failed to make us a subreaper of our children");
3508
3509+ // Raise our process priority to be as fast as possible
3510+ setpriority(PRIO_PROCESS, 0, kProcessPriorityUrgentDisplay);
3511+
3512 network_manager = mcs::NetworkManagerFactory::Create();
3513 service = mcs::MiracastService::Create(network_manager);
3514 mcsa = mcs::MiracastControllerSkeleton::create(service);
3515@@ -202,6 +216,8 @@
3516 network_manager_->Setup();
3517 }
3518
3519+ system_controller_ = mcs::SystemController::CreatePlatformDefault();
3520+
3521 return shared_from_this();
3522 }
3523
3524@@ -246,8 +262,6 @@
3525 }
3526
3527 void MiracastService::AdvanceState(NetworkDeviceState new_state) {
3528- IpV4Address address;
3529-
3530 DEBUG("new state %s current state %s",
3531 mcs::NetworkDevice::StateToStr(new_state),
3532 mcs::NetworkDevice::StateToStr(current_state_));
3533@@ -256,13 +270,12 @@
3534 case kAssociation:
3535 break;
3536
3537+ case kConfiguration:
3538+ break;
3539+
3540 case kConnected:
3541- address = network_manager_->LocalAddress();
3542-
3543- source_ = MiracastSourceManager::Create(address, kMiracastDefaultRtspCtrlPort);
3544-
3545+ source_ = MiracastSourceManager::Create(network_manager_->LocalAddress(), kMiracastDefaultRtspCtrlPort);
3546 FinishConnectAttempt();
3547-
3548 break;
3549
3550 case kFailure:
3551@@ -272,6 +285,8 @@
3552 source_.reset();
3553 current_device_.reset();
3554
3555+ system_controller_->DisplayStateLock()->Release(mcs::DisplayState::On);
3556+
3557 StartIdleTimer();
3558 break;
3559
3560@@ -359,6 +374,8 @@
3561 return;
3562 }
3563
3564+ system_controller_->DisplayStateLock()->Acquire(mcs::DisplayState::On);
3565+
3566 current_device_ = device;
3567 connect_callback_ = callback;
3568 }
3569@@ -377,8 +394,17 @@
3570 callback(Error::kNone);
3571 }
3572
3573-void MiracastService::Scan(const std::chrono::seconds &timeout) {
3574+void MiracastService::DisconnectAll(ResultCallback callback) {
3575+ Disconnect(current_device_, callback);
3576+}
3577+
3578+mcs::Error MiracastService::Scan(const std::chrono::seconds &timeout) {
3579+ if (current_device_)
3580+ return mcs::Error::kInvalidState;
3581+
3582 network_manager_->Scan(timeout);
3583+
3584+ return mcs::Error::kNone;
3585 }
3586
3587 void MiracastService::Shutdown() {
3588
3589=== modified file 'src/mcs/miracastservice.h'
3590--- src/mcs/miracastservice.h 2016-01-21 13:25:31 +0000
3591+++ src/mcs/miracastservice.h 2016-02-25 12:47:02 +0000
3592@@ -32,6 +32,7 @@
3593 #include "networkdevice.h"
3594 #include "non_copyable.h"
3595 #include "types.h"
3596+#include "systemcontroller.h"
3597
3598 namespace mcs {
3599 class MiracastService : public MiracastController,
3600@@ -64,7 +65,9 @@
3601 void Connect(const NetworkDevice::Ptr &device, ResultCallback callback);
3602 void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback);
3603
3604- void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30});
3605+ void DisconnectAll(ResultCallback callback);
3606+
3607+ mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30});
3608
3609 NetworkDeviceState State() const;
3610 std::vector<NetworkManager::Capability> Capabilities() const;
3611@@ -104,6 +107,7 @@
3612 guint scan_timeout_source_;
3613 ResultCallback current_scan_callback_;
3614 std::vector<NetworkDeviceRole> supported_roles_;
3615+ mcs::SystemController::Ptr system_controller_;
3616 };
3617 } // namespace mcs
3618 #endif
3619
3620=== modified file 'src/mcs/miracastsourceclient.cpp'
3621--- src/mcs/miracastsourceclient.cpp 2015-12-09 16:07:13 +0000
3622+++ src/mcs/miracastsourceclient.cpp 2016-02-25 12:47:02 +0000
3623@@ -25,7 +25,7 @@
3624 #include "keep_alive.h"
3625 #include "logger.h"
3626 #include "miracastsourceclient.h"
3627-#include "mirsourcemediamanager.h"
3628+#include "mcs/mir/sourcemediamanager.h"
3629 #include "testsourcemediamanager.h"
3630 #include "mediamanagerfactory.h"
3631
3632@@ -34,14 +34,15 @@
3633 #include "logging.h"
3634
3635 namespace mcs {
3636-std::shared_ptr<MiracastSourceClient> MiracastSourceClient::Create(ScopedGObject<GSocket>&& socket) {
3637- std::shared_ptr<MiracastSourceClient> sp{new MiracastSourceClient{std::move(socket)}};
3638+std::shared_ptr<MiracastSourceClient> MiracastSourceClient::Create(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address) {
3639+ std::shared_ptr<MiracastSourceClient> sp{new MiracastSourceClient{std::move(socket), local_address}};
3640 return sp->FinalizeConstruction();
3641 }
3642
3643-MiracastSourceClient::MiracastSourceClient(ScopedGObject<GSocket>&& socket) :
3644+MiracastSourceClient::MiracastSourceClient(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address) :
3645 socket_(std::move(socket)),
3646- socket_source_(0) {
3647+ socket_source_(0),
3648+ local_address_(local_address) {
3649 }
3650
3651 MiracastSourceClient::~MiracastSourceClient() {
3652@@ -82,7 +83,15 @@
3653 }
3654
3655 std::string MiracastSourceClient::GetLocalIPAddress() const {
3656- return local_address_;
3657+ return local_address_.to_string();
3658+}
3659+
3660+int MiracastSourceClient::GetNextCSeq(int *initial_peer_cseq) const {
3661+ static int send_cseq = 0;
3662+ ++send_cseq;
3663+ if (initial_peer_cseq && send_cseq == *initial_peer_cseq)
3664+ send_cseq *= 2;
3665+ return send_cseq;
3666 }
3667
3668 class TimerCallbackData {
3669
3670=== modified file 'src/mcs/miracastsourceclient.h'
3671--- src/mcs/miracastsourceclient.h 2015-12-07 09:07:50 +0000
3672+++ src/mcs/miracastsourceclient.h 2016-02-25 12:47:02 +0000
3673@@ -31,8 +31,9 @@
3674 #include <wds/source.h>
3675 #include <wds/media_manager.h>
3676
3677-#include "non_copyable.h"
3678-#include "scoped_gobject.h"
3679+#include "mcs/ip_v4_address.h"
3680+#include "mcs/non_copyable.h"
3681+#include "mcs/scoped_gobject.h"
3682
3683 namespace mcs {
3684 class TimerCallbackData;
3685@@ -45,7 +46,7 @@
3686 virtual void OnConnectionClosed() = 0;
3687 };
3688
3689- static std::shared_ptr<MiracastSourceClient> Create(ScopedGObject<GSocket>&& socket);
3690+ static std::shared_ptr<MiracastSourceClient> Create(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address);
3691
3692 ~MiracastSourceClient();
3693
3694@@ -57,6 +58,7 @@
3695 std::string GetLocalIPAddress() const override;
3696 uint CreateTimer(int seconds) override;
3697 void ReleaseTimer(uint timerId) override;
3698+ int GetNextCSeq(int* initial_peer_cseq = nullptr) const override;
3699
3700 public:
3701 static gboolean OnTimeout(gpointer user_data);
3702@@ -65,7 +67,7 @@
3703 gpointer user_data);
3704
3705 private:
3706- MiracastSourceClient(ScopedGObject<GSocket>&& socket);
3707+ MiracastSourceClient(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address);
3708 std::shared_ptr<MiracastSourceClient> FinalizeConstruction();
3709
3710 void DumpRtsp(const std::string &prefix, const std::string &data);
3711@@ -75,7 +77,7 @@
3712 std::weak_ptr<Delegate> delegate_;
3713 ScopedGObject<GSocket> socket_;
3714 guint socket_source_;
3715- std::string local_address_;
3716+ mcs::IpV4Address local_address_;
3717 std::vector<guint> timers_;
3718 std::unique_ptr<wds::Source> source_;
3719 std::shared_ptr<wds::SourceMediaManager> media_manager_;
3720
3721=== modified file 'src/mcs/miracastsourcemanager.cpp'
3722--- src/mcs/miracastsourcemanager.cpp 2016-01-16 13:40:27 +0000
3723+++ src/mcs/miracastsourcemanager.cpp 2016-02-25 12:47:02 +0000
3724@@ -22,7 +22,7 @@
3725 #include "logging.h"
3726
3727 namespace mcs {
3728-std::shared_ptr<MiracastSourceManager> MiracastSourceManager::Create(const IpV4Address &address, unsigned short port) {
3729+std::shared_ptr<MiracastSourceManager> MiracastSourceManager::Create(const mcs::IpV4Address &address, unsigned short port) {
3730 auto sp = std::shared_ptr<MiracastSourceManager>{new MiracastSourceManager{}};
3731 sp->Setup(address, port);
3732 return sp;
3733@@ -49,7 +49,7 @@
3734 delegate_.reset();
3735 }
3736
3737-bool MiracastSourceManager::Setup(const IpV4Address &address, unsigned short port) {
3738+bool MiracastSourceManager::Setup(const mcs::IpV4Address &address, unsigned short port) {
3739 GError *error = nullptr;
3740
3741 if (socket_)
3742@@ -97,8 +97,9 @@
3743
3744 g_source_unref(source);
3745
3746- DEBUG("Successfully setup source on %s:%d and awaiting incoming connection requests",
3747- address.to_string(), port);
3748+ DEBUG("Successfully setup source on %s:%d and awaiting incoming connection requests", address.to_string(), port);
3749+
3750+ local_address_ = address;
3751
3752 socket_.swap(socket);
3753
3754@@ -132,7 +133,7 @@
3755 return TRUE;
3756 }
3757
3758- inst->active_sink_ = MiracastSourceClient::Create(ScopedGObject<GSocket>{client_socket});
3759+ inst->active_sink_ = MiracastSourceClient::Create(ScopedGObject<GSocket>{client_socket}, inst->local_address_);
3760 inst->active_sink_->SetDelegate(inst->shared_from_this());
3761
3762 return TRUE;
3763
3764=== modified file 'src/mcs/miracastsourcemanager.h'
3765--- src/mcs/miracastsourcemanager.h 2015-12-09 16:07:13 +0000
3766+++ src/mcs/miracastsourcemanager.h 2016-02-25 12:47:02 +0000
3767@@ -41,7 +41,7 @@
3768 Delegate() = default;
3769 };
3770
3771- static std::shared_ptr<MiracastSourceManager> Create(const IpV4Address &address, unsigned short port);
3772+ static std::shared_ptr<MiracastSourceManager> Create(const mcs::IpV4Address &address, unsigned short port);
3773
3774 ~MiracastSourceManager();
3775
3776@@ -56,13 +56,14 @@
3777
3778 MiracastSourceManager();
3779
3780- bool Setup(const IpV4Address &address, unsigned short port);
3781+ bool Setup(const mcs::IpV4Address &address, unsigned short port);
3782
3783 private:
3784 std::weak_ptr<Delegate> delegate_;
3785 ScopedGObject<GSocket> socket_;
3786 guint socket_source_;
3787 std::shared_ptr<MiracastSourceClient> active_sink_;
3788+ mcs::IpV4Address local_address_;
3789 };
3790 } // namespace mcs
3791 #endif
3792
3793=== removed file 'src/mcs/networkdeviceskeleton.cpp'
3794--- src/mcs/networkdeviceskeleton.cpp 2016-01-21 13:25:31 +0000
3795+++ src/mcs/networkdeviceskeleton.cpp 1970-01-01 00:00:00 +0000
3796@@ -1,142 +0,0 @@
3797-/*
3798- * Copyright (C) 2015 Canonical, Ltd.
3799- *
3800- * This program is free software: you can redistribute it and/or modify it
3801- * under the terms of the GNU General Public License version 3, as published
3802- * by the Free Software Foundation.
3803- *
3804- * This program is distributed in the hope that it will be useful, but
3805- * WITHOUT ANY WARRANTY; without even the implied warranties of
3806- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3807- * PURPOSE. See the GNU General Public License for more details.
3808- *
3809- * You should have received a copy of the GNU General Public License along
3810- * with this program. If not, see <http://www.gnu.org/licenses/>.
3811- *
3812- */
3813-
3814-#include <algorithm>
3815-#include <boost/concept_check.hpp>
3816-
3817-#include "networkdeviceskeleton.h"
3818-#include "utils.h"
3819-#include "keep_alive.h"
3820-#include "logger.h"
3821-#include "dbushelpers.h"
3822-
3823-namespace mcs {
3824-
3825-NetworkDeviceSkeleton::Ptr NetworkDeviceSkeleton::Create(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) {
3826- return std::shared_ptr<NetworkDeviceSkeleton>(new NetworkDeviceSkeleton(connection, path, device, controller))->FinalizeConstruction();
3827-}
3828-
3829-NetworkDeviceSkeleton::NetworkDeviceSkeleton(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) :
3830- ForwardingNetworkDevice(device),
3831- connection_(connection),
3832- object_(make_shared_gobject(aethercast_interface_object_skeleton_new(path.c_str()))),
3833- path_(path),
3834- controller_(controller),
3835- device_iface_(aethercast_interface_device_skeleton_new()) {
3836-}
3837-
3838-std::shared_ptr<NetworkDeviceSkeleton> NetworkDeviceSkeleton::FinalizeConstruction() {
3839- auto sp = shared_from_this();
3840-
3841- g_signal_connect(device_iface_.get(), "handle-connect",
3842- G_CALLBACK(&NetworkDeviceSkeleton::OnHandleConnect),
3843- new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
3844- g_signal_connect(device_iface_.get(), "handle-disconnect",
3845- G_CALLBACK(&NetworkDeviceSkeleton::OnHandleDisconnect),
3846- new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
3847-
3848- SyncProperties();
3849-
3850- if (!object_)
3851- ERROR("Failed to create object for device %s", Address());
3852- else
3853- aethercast_interface_object_skeleton_set_device(object_.get(), device_iface_.get());
3854-
3855- return sp;
3856-}
3857-
3858-void NetworkDeviceSkeleton::SyncProperties() {
3859- aethercast_interface_device_set_address(device_iface_.get(), Address().c_str());
3860- aethercast_interface_device_set_name(device_iface_.get(), Name().c_str());
3861- aethercast_interface_device_set_state(device_iface_.get(), NetworkDevice::StateToStr(State()).c_str());
3862-
3863- auto capabilities = DBusHelpers::GenerateDeviceCapabilities(SupportedRoles());
3864- aethercast_interface_device_set_capabilities(device_iface_.get(), capabilities);
3865- g_strfreev(capabilities);
3866-}
3867-
3868-GDBusObjectSkeleton* NetworkDeviceSkeleton::DBusObject() const {
3869- return G_DBUS_OBJECT_SKELETON(object_.get());
3870-}
3871-
3872-std::string NetworkDeviceSkeleton::Path() const {
3873- return path_;
3874-}
3875-
3876-// TODO(tvoss,morphis): Refactor mcs::NetworkDevice to have Connect/Disconnect defined on its interfaces.
3877-// It feels quite dirty to require both an instance of mcs::NetworkDevice and mcs::MiracastController to
3878-// implement the connect/disconnect calls coming in via the bus. The complication then is the async handling of
3879-// the invocation, as we will likely have to reach out to WPASupplicant for example (which is dispatched via the same
3880-// event loop as we are). In addition, we should not start littering our public interfaces by handing down callbacks.
3881-gboolean NetworkDeviceSkeleton::OnHandleConnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
3882- const gchar *role, gpointer user_data)
3883-{
3884- boost::ignore_unused_variable_warning(skeleton);
3885- boost::ignore_unused_variable_warning(role);
3886-
3887- auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
3888-
3889- if (not inst) {
3890- g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
3891- return TRUE;
3892- }
3893-
3894- g_object_ref(invocation);
3895- auto inv = make_shared_gobject(invocation);
3896-
3897- inst->controller_->Connect(inst->Fwd(), [inv](mcs::Error error) {
3898- if (error != Error::kNone) {
3899- g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3900- "%s", mcs::ErrorToString(error).c_str());
3901- return;
3902- }
3903-
3904- g_dbus_method_invocation_return_value(inv.get(), nullptr);
3905- });
3906-
3907- return TRUE;
3908-}
3909-
3910-gboolean NetworkDeviceSkeleton::OnHandleDisconnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
3911- gpointer user_data)
3912-{
3913- boost::ignore_unused_variable_warning(skeleton);
3914-
3915- auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
3916-
3917- if (not inst) {
3918- g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
3919- return TRUE;
3920- }
3921-
3922- g_object_ref(invocation);
3923- auto inv = make_shared_gobject(invocation);
3924-
3925- inst->controller_->Disconnect(inst->Fwd(), [inv](mcs::Error error) {
3926- if (error != Error::kNone) {
3927- g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3928- "%s", mcs::ErrorToString(error).c_str());
3929- return;
3930- }
3931-
3932- g_dbus_method_invocation_return_value(inv.get(), nullptr);
3933- });
3934-
3935- return TRUE;
3936-}
3937-
3938-} // namespace mcs
3939
3940=== modified file 'src/mcs/networkutils.cpp'
3941--- src/mcs/networkutils.cpp 2016-01-15 19:31:22 +0000
3942+++ src/mcs/networkutils.cpp 2016-02-25 12:47:02 +0000
3943@@ -15,17 +15,28 @@
3944 *
3945 */
3946
3947+
3948 #include <sys/ioctl.h>
3949-#include <net/if.h>
3950 #include <asm/types.h>
3951-#include <linux/netlink.h>
3952-#include <linux/rtnetlink.h>
3953 #include <sys/socket.h>
3954 #include <netinet/in.h>
3955 #include <arpa/inet.h>
3956 #include <unistd.h>
3957 #include <errno.h>
3958 #include <memory.h>
3959+#include <stdlib.h>
3960+#include <errno.h>
3961+
3962+#include <linux/netlink.h>
3963+#include <linux/rtnetlink.h>
3964+
3965+// Hacks necessary to be able to include wireless.h
3966+#ifndef __user
3967+#define __user
3968+#endif
3969+
3970+#include <linux/if.h>
3971+#include <linux/wireless.h>
3972
3973 #include <glib.h>
3974
3975@@ -33,6 +44,9 @@
3976 #include "networkutils.h"
3977 #include "logger.h"
3978
3979+namespace {
3980+static constexpr size_t kDriverCommandReplySize{1024};
3981+
3982 #define NLMSG_TAIL(nmsg) \
3983 ((struct rtattr *) (((uint8_t*) (nmsg)) + \
3984 NLMSG_ALIGN((nmsg)->nlmsg_len)))
3985@@ -56,6 +70,7 @@
3986
3987 return 0;
3988 }
3989+}
3990
3991 namespace mcs {
3992 int NetworkUtils::ModifyInterfaceAddress(int cmd, int flags,
3993@@ -259,4 +274,47 @@
3994 available = (int64_t) nbytes;
3995 return available;
3996 }
3997+
3998+typedef struct {
3999+#ifdef SUPPORT_64BIT
4000+ u64 bufaddr;
4001+#else
4002+ char *bufaddr;
4003+#endif
4004+ int used_len;
4005+ int total_len;
4006+} android_wifi_priv_cmd;
4007+
4008+int NetworkUtils::SendDriverPrivateCommand(const std::string &ifname, const std::string &cmd) {
4009+ struct ifreq ifr;
4010+ int ret = 0, s;
4011+ android_wifi_priv_cmd priv_cmd;
4012+ char buf[kDriverCommandReplySize];
4013+ size_t buf_len = kDriverCommandReplySize;
4014+
4015+ ::memset(buf, 0, sizeof(buf));
4016+ ::memcpy(buf, cmd.c_str(), cmd.length() + 1);
4017+ ::memset(&ifr, 0, sizeof(ifr));
4018+ ::memset(&priv_cmd, 0, sizeof(priv_cmd));
4019+
4020+ ::strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
4021+
4022+#ifdef SUPPORT_64BIT
4023+ priv_cmd.bufaddr = (u64)(uintptr_t) buf;
4024+#else
4025+ priv_cmd.bufaddr = buf;
4026+#endif
4027+ priv_cmd.used_len = buf_len;
4028+ priv_cmd.total_len = buf_len;
4029+ ifr.ifr_data = &priv_cmd;
4030+
4031+ s = ::socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
4032+ if (s < 0)
4033+ return -EIO;
4034+
4035+ ret = ::ioctl(s, SIOCDEVPRIVATE + 1, &ifr);
4036+ ::close(s);
4037+ return ret;
4038+}
4039+
4040 } // namespace mcs
4041
4042=== modified file 'src/mcs/networkutils.h'
4043--- src/mcs/networkutils.h 2016-01-15 19:31:22 +0000
4044+++ src/mcs/networkutils.h 2016-02-25 12:47:02 +0000
4045@@ -18,6 +18,8 @@
4046 #ifndef NETWORKUTILS_H_
4047 #define NETWORKUTILS_H_
4048
4049+#include <string>
4050+
4051 namespace mcs {
4052 class NetworkUtils
4053 {
4054@@ -29,6 +31,7 @@
4055 unsigned char prefixlen, const char *broadcast);
4056 static int ResetInterface(int index);
4057 static int BytesAvailableToRead(int fd);
4058+ static int SendDriverPrivateCommand(const std::string &ifname, const std::string &cmd);
4059 };
4060 } // namespace mcs
4061 #endif
4062
4063=== added directory 'src/mcs/streaming'
4064=== added file 'src/mcs/streaming/mpegtspacketizer.cpp'
4065--- src/mcs/streaming/mpegtspacketizer.cpp 1970-01-01 00:00:00 +0000
4066+++ src/mcs/streaming/mpegtspacketizer.cpp 2016-02-25 12:47:02 +0000
4067@@ -0,0 +1,831 @@
4068+/*
4069+ * Copyright 2012, The Android Open Source Project
4070+ * Copyright (C) 2016 Canonical, Ltd.
4071+ *
4072+ * Licensed under the Apache License, Version 2.0 (the "License");
4073+ * you may not use this file except in compliance with the License.
4074+ * You may obtain a copy of the License at
4075+ *
4076+ * http://www.apache.org/licenses/LICENSE-2.0
4077+ *
4078+ * Unless required by applicable law or agreed to in writing, software
4079+ * distributed under the License is distributed on an "AS IS" BASIS,
4080+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4081+ * See the License for the specific language governing permissions and
4082+ * limitations under the License.
4083+ */
4084+
4085+/**
4086+ * NOTE: The implementation is based on the Android implementation for WiFi
4087+ * display support in frameworks/av/libstagefright/wifi-display/TSPacketizer.cpp
4088+ * and is adjusted for our needs.
4089+ */
4090+
4091+#include <arpa/inet.h>
4092+#include <memory.h>
4093+
4094+#include "mcs/utils.h"
4095+#include "mcs/logger.h"
4096+
4097+#include "mcs/video/utils.h"
4098+
4099+#include "mcs/streaming/mpegtspacketizer.h"
4100+
4101+namespace {
4102+const unsigned int kPIDofPMT = 0x100;
4103+const unsigned int kPIDofPCR = 0x1000;
4104+}
4105+
4106+namespace mcs {
4107+namespace streaming {
4108+
4109+struct MPEGTSPacketizer::Track {
4110+ typedef std::shared_ptr<Track> Ptr;
4111+
4112+ static Ptr Create(const TrackFormat &format, unsigned int pid,
4113+ unsigned int stream_type, unsigned int stream_id);
4114+
4115+ unsigned int PID() const { return pid_; }
4116+ unsigned int StreamType() const { return stream_type_; }
4117+ unsigned int StreamId() const { return stream_id_; }
4118+ TrackFormat Format() const { return format_; }
4119+
4120+ unsigned int NextContinuityCounter();
4121+
4122+ bool IsAudio() const { return mcs::Utils::StringStartsWith(format_.mime, "audio/"); }
4123+ bool IsVideo() const { return mcs::Utils::StringStartsWith(format_.mime, "video/"); }
4124+
4125+ bool IsH264() const { return format_.mime == "video/avc"; }
4126+
4127+ void SubmitCSD(const mcs::video::Buffer::Ptr &buffer);
4128+
4129+ mcs::video::Buffer::Ptr PrependCSD(const mcs::video::Buffer::Ptr &buffer) const;
4130+
4131+ void Finalize();
4132+
4133+ std::vector<mcs::video::Buffer::Ptr> Descriptors() const { return descriptors_; }
4134+
4135+private:
4136+ Track(const TrackFormat &format, unsigned int pid,
4137+ unsigned int stream_type, unsigned int stream_id);
4138+
4139+private:
4140+ TrackFormat format_;
4141+ unsigned int pid_;
4142+ unsigned int stream_type_;
4143+ unsigned int stream_id_;
4144+ unsigned int continuity_counter_;
4145+ bool finalized_;
4146+ std::vector<mcs::video::Buffer::Ptr> csd_;
4147+ std::vector<mcs::video::Buffer::Ptr> descriptors_;
4148+};
4149+
4150+MPEGTSPacketizer::Track::Ptr MPEGTSPacketizer::Track::Create(const TrackFormat &format, unsigned int pid,
4151+ unsigned int stream_type, unsigned int stream_id) {
4152+ return std::shared_ptr<Track>(new Track(format, pid, stream_type, stream_id));
4153+}
4154+
4155+MPEGTSPacketizer::Track::Track(const TrackFormat &format, unsigned int pid,
4156+ unsigned int stream_type, unsigned int stream_id) :
4157+ format_(format),
4158+ pid_(pid),
4159+ stream_type_(stream_type),
4160+ stream_id_(stream_id),
4161+ continuity_counter_(0),
4162+ finalized_(false) {
4163+}
4164+
4165+unsigned int MPEGTSPacketizer::Track::NextContinuityCounter() {
4166+ unsigned int prev = continuity_counter_;
4167+ if (++continuity_counter_ == 16)
4168+ continuity_counter_ = 0;
4169+ return prev;
4170+}
4171+
4172+void MPEGTSPacketizer::Track::SubmitCSD(const video::Buffer::Ptr &buffer) {
4173+ if (!IsH264())
4174+ return;
4175+
4176+ const uint8_t *data = buffer->Data();
4177+ size_t size = buffer->Length();
4178+
4179+ const uint8_t *nal_start;
4180+ size_t nal_size;
4181+
4182+ while (mcs::video::GetNextNALUnit(&data, &size, &nal_start, &nal_size, true)) {
4183+ auto csd = mcs::video::Buffer::Create(nal_size + 4);
4184+
4185+ ::memcpy(csd->Data(), "\x00\x00\x00\x01", 4);
4186+ ::memcpy(csd->Data() + 4, nal_start, nal_size);
4187+
4188+ csd_.push_back(csd);
4189+ }
4190+}
4191+
4192+mcs::video::Buffer::Ptr MPEGTSPacketizer::Track::PrependCSD(const mcs::video::Buffer::Ptr &buffer) const {
4193+ size_t size = 0;
4194+ for (auto csd : csd_)
4195+ size += csd->Length();
4196+
4197+ auto new_buffer = mcs::video::Buffer::Create(buffer->Length() + size);
4198+ size_t offset = 0;
4199+ for (auto csd : csd_) {
4200+ ::memcpy(new_buffer->Data() + offset, csd->Data(), csd->Length());
4201+ offset += csd->Length();
4202+ }
4203+
4204+ ::memcpy(new_buffer->Data() + offset, buffer->Data(), buffer->Length());
4205+
4206+ return new_buffer;
4207+}
4208+
4209+void MPEGTSPacketizer::Track::Finalize() {
4210+ if (finalized_)
4211+ return;
4212+
4213+ if(!IsH264())
4214+ return;
4215+
4216+ MCS_DEBUG("");
4217+
4218+ {
4219+ // AVC video descriptor (40)
4220+ auto descriptor = mcs::video::Buffer::Create(6);
4221+ uint8_t *data = descriptor->Data();
4222+ data[0] = 40; // descriptor_tag
4223+ data[1] = 4; // descriptor_length
4224+
4225+ if (csd_.size() > 0) {
4226+ // Seems to be a conventation that the first NAL we get
4227+ // submitted as part of the codec-specific data is the
4228+ // SPS we want here.
4229+ auto sps = csd_.at(0);
4230+ // We skip the first four bytes (NAL preamble) and then
4231+ // just copy profile/constraint/level settings
4232+ memcpy(&data[2], sps->Data() + 4, 3);
4233+ }
4234+ else {
4235+ data[2] = format_.profile_idc; // profile_idc
4236+ data[3] = format_.constraint_set; // constraint_set*
4237+ data[4] = format_.level_idc; // level_idc
4238+ }
4239+
4240+ // AVC_still_present=0, AVC_24_hour_picture_flag=0, reserved
4241+ data[5] = 0x3f;
4242+
4243+ descriptors_.push_back(descriptor);
4244+ }
4245+ {
4246+ // AVC timing and HRD descriptor (42)
4247+
4248+ auto descriptor = mcs::video::Buffer::Create(4);
4249+ uint8_t *data = descriptor->Data();
4250+ data[0] = 42; // descriptor_tag
4251+ data[1] = 2; // descriptor_length
4252+
4253+ // hrd_management_valid_flag = 0
4254+ // reserved = 111111b
4255+ // picture_and_timing_info_present = 0
4256+
4257+ data[2] = 0x7e;
4258+
4259+ // fixed_frame_rate_flag = 0
4260+ // temporal_poc_flag = 0
4261+ // picture_to_display_conversion_flag = 0
4262+ // reserved = 11111b
4263+ data[3] = 0x1f;
4264+
4265+ descriptors_.push_back(descriptor);
4266+ }
4267+
4268+ finalized_ = true;
4269+}
4270+
4271+MPEGTSPacketizer::Ptr MPEGTSPacketizer::Create() {
4272+ return std::shared_ptr<MPEGTSPacketizer>(new MPEGTSPacketizer);
4273+}
4274+
4275+MPEGTSPacketizer::MPEGTSPacketizer() :
4276+ pat_continuity_counter_(0),
4277+ pmt_continuity_counter_(0) {
4278+ InitCrcTable();
4279+}
4280+
4281+MPEGTSPacketizer::~MPEGTSPacketizer() {
4282+}
4283+
4284+MPEGTSPacketizer::TrackId MPEGTSPacketizer::AddTrack(const TrackFormat &format) {
4285+ auto is_video = mcs::Utils::StringStartsWith(format.mime, "video/");
4286+
4287+ if (!is_video) {
4288+ MCS_ERROR("Audio tracks for MPEGTS are currently not supported");
4289+ return TrackId(-1);
4290+ }
4291+
4292+ if (format.mime != "video/avc") {
4293+ MCS_ERROR("Video formats other than video/avc are not supported");
4294+ return TrackId(-1);
4295+ }
4296+
4297+ // First PID as per WiFi Display spec
4298+ unsigned int pid_start = 0x1011;
4299+ unsigned int stream_type = 0x1b;
4300+ unsigned int stream_id_start = 0xe0;
4301+ unsigned int stream_id_stop = 0xef;
4302+
4303+ unsigned int num_same_tracks = 0;
4304+ unsigned int pid = pid_start;
4305+
4306+ for (auto track : tracks_) {
4307+ if (track->StreamType() == stream_type)
4308+ num_same_tracks++;
4309+
4310+ if (track->IsAudio() || track->IsVideo())
4311+ pid++;
4312+ }
4313+
4314+ unsigned int stream_id = stream_id_start + num_same_tracks;
4315+ if (stream_id > stream_id_stop) {
4316+ MCS_ERROR("All stream ids are in use");
4317+ return TrackId(-1);
4318+ }
4319+
4320+ auto track = Track::Create(format, pid, stream_type, stream_id);
4321+ tracks_.push_back(track);
4322+
4323+ return tracks_.size() - 1;
4324+}
4325+
4326+void MPEGTSPacketizer::SubmitCSD(TrackId track_index, const video::Buffer::Ptr &buffer) {
4327+ if (track_index > tracks_.size() -1)
4328+ return;
4329+
4330+ auto track = tracks_.at(track_index);
4331+ track->SubmitCSD(buffer);
4332+}
4333+
4334+bool MPEGTSPacketizer::Packetize(TrackId track_index, const video::Buffer::Ptr &_access_unit,
4335+ video::Buffer::Ptr *packets, int flags) {
4336+ size_t numStuffingBytes = 0;
4337+ const uint8_t *PES_private_data = nullptr;
4338+ size_t PES_private_data_len = 0;
4339+ mcs::video::Buffer::Ptr access_unit = _access_unit;
4340+ int64_t timeUs = access_unit->Timestamp();
4341+
4342+ packets->reset();
4343+
4344+ if (track_index > tracks_.size() - 1) {
4345+ MCS_ERROR("Invalid track index %d supplied", track_index);
4346+ return false;
4347+ }
4348+
4349+ auto track = tracks_.at(track_index);
4350+
4351+ if (track->IsH264() && (flags & Flags::kPrependSPSandPPStoIDRFrames)
4352+ && mcs::video::DoesBufferContainIDRFrame(access_unit)) {
4353+ // prepend codec specific data, i.e. SPS and PPS.
4354+ access_unit = track->PrependCSD(access_unit);
4355+ }
4356+
4357+ // 0x47
4358+ // transport_error_indicator = b0
4359+ // payload_unit_start_indicator = b1
4360+ // transport_priority = b0
4361+ // PID
4362+ // transport_scrambling_control = b00
4363+ // adaptation_field_control = b??
4364+ // continuity_counter = b????
4365+ // -- payload follows
4366+ // packet_startcode_prefix = 0x000001
4367+ // stream_id
4368+ // PES_packet_length = 0x????
4369+ // reserved = b10
4370+ // PES_scrambling_control = b00
4371+ // PES_priority = b0
4372+ // data_alignment_indicator = b1
4373+ // copyright = b0
4374+ // original_or_copy = b0
4375+ // PTS_DTS_flags = b10 (PTS only)
4376+ // ESCR_flag = b0
4377+ // ES_rate_flag = b0
4378+ // DSM_trick_mode_flag = b0
4379+ // additional_copy_info_flag = b0
4380+ // PES_CRC_flag = b0
4381+ // PES_extension_flag = b0
4382+ // PES_header_data_length = 0x05
4383+ // reserved = b0010 (PTS)
4384+ // PTS[32..30] = b???
4385+ // reserved = b1
4386+ // PTS[29..15] = b??? ???? ???? ???? (15 bits)
4387+ // reserved = b1
4388+ // PTS[14..0] = b??? ???? ???? ???? (15 bits)
4389+ // reserved = b1
4390+ // the first fragment of "buffer" follows
4391+
4392+ // Each transport packet (except for the last one contributing to the PES
4393+ // payload) must contain a multiple of 16 bytes of payload per HDCP spec.
4394+ bool alignPayload = false;
4395+
4396+ /*
4397+ a) The very first PES transport stream packet contains
4398+
4399+ 4 bytes of TS header
4400+ ... padding
4401+ 14 bytes of static PES header
4402+ PES_private_data_len + 1 bytes (only if PES_private_data_len > 0)
4403+ numStuffingBytes bytes
4404+
4405+ followed by the payload
4406+
4407+ b) Subsequent PES transport stream packets contain
4408+
4409+ 4 bytes of TS header
4410+ ... padding
4411+
4412+ followed by the payload
4413+ */
4414+
4415+ size_t PES_packet_length = access_unit->Length() + 8 + numStuffingBytes;
4416+ if (PES_private_data_len > 0)
4417+ PES_packet_length += PES_private_data_len + 1;
4418+
4419+ size_t numTSPackets = 1;
4420+
4421+ {
4422+ // Make sure the PES header fits into a single TS packet:
4423+ size_t PES_header_size = 14 + numStuffingBytes;
4424+ if (PES_private_data_len > 0) {
4425+ PES_header_size += PES_private_data_len + 1;
4426+ }
4427+
4428+ if (PES_header_size > 188u - 4u)
4429+ MCS_FATAL("Invalid header size");
4430+
4431+ size_t sizeAvailableForPayload = 188 - 4 - PES_header_size;
4432+ size_t numBytesOfPayload = access_unit->Length();
4433+
4434+ if (numBytesOfPayload > sizeAvailableForPayload) {
4435+ numBytesOfPayload = sizeAvailableForPayload;
4436+
4437+ if (alignPayload && numBytesOfPayload > 16) {
4438+ numBytesOfPayload -= (numBytesOfPayload % 16);
4439+ }
4440+ }
4441+
4442+ size_t numBytesOfPayloadRemaining = access_unit->Length() - numBytesOfPayload;
4443+
4444+ // This is how many bytes of payload each subsequent TS packet
4445+ // can contain at most.
4446+ sizeAvailableForPayload = 188 - 4;
4447+ size_t sizeAvailableForAlignedPayload = sizeAvailableForPayload;
4448+ if (alignPayload) {
4449+ // We're only going to use a subset of the available space
4450+ // since we need to make each fragment a multiple of 16 in size.
4451+ sizeAvailableForAlignedPayload -=
4452+ (sizeAvailableForAlignedPayload % 16);
4453+ }
4454+
4455+ size_t numFullTSPackets =
4456+ numBytesOfPayloadRemaining / sizeAvailableForAlignedPayload;
4457+
4458+ numTSPackets += numFullTSPackets;
4459+
4460+ numBytesOfPayloadRemaining -=
4461+ numFullTSPackets * sizeAvailableForAlignedPayload;
4462+
4463+ // numBytesOfPayloadRemaining < sizeAvailableForAlignedPayload
4464+ if (numFullTSPackets == 0 && numBytesOfPayloadRemaining > 0) {
4465+ // There wasn't enough payload left to form a full aligned payload,
4466+ // the last packet doesn't have to be aligned.
4467+ ++numTSPackets;
4468+ } else if (numFullTSPackets > 0
4469+ && numBytesOfPayloadRemaining
4470+ + sizeAvailableForAlignedPayload > sizeAvailableForPayload) {
4471+ // The last packet emitted had a full aligned payload and together
4472+ // with the bytes remaining does exceed the unaligned payload
4473+ // size, so we need another packet.
4474+ ++numTSPackets;
4475+ }
4476+ }
4477+
4478+ if (flags & Flags::kEmitPATandPMT)
4479+ numTSPackets += 2;
4480+
4481+ if (flags & Flags::kEmitPCR)
4482+ ++numTSPackets;
4483+
4484+ auto buffer = mcs::video::Buffer::Create(numTSPackets * 188);
4485+ buffer->SetTimestamp(access_unit->Timestamp());
4486+
4487+ uint8_t *packetDataStart = buffer->Data();
4488+
4489+ if (flags & Flags::kEmitPATandPMT) {
4490+ // Program Association Table (PAT):
4491+ // 0x47
4492+ // transport_error_indicator = b0
4493+ // payload_unit_start_indicator = b1
4494+ // transport_priority = b0
4495+ // PID = b0000000000000 (13 bits)
4496+ // transport_scrambling_control = b00
4497+ // adaptation_field_control = b01 (no adaptation field, payload only)
4498+ // continuity_counter = b????
4499+ // skip = 0x00
4500+ // --- payload follows
4501+ // table_id = 0x00
4502+ // section_syntax_indicator = b1
4503+ // must_be_zero = b0
4504+ // reserved = b11
4505+ // section_length = 0x00d
4506+ // transport_stream_id = 0x0000
4507+ // reserved = b11
4508+ // version_number = b00001
4509+ // current_next_indicator = b1
4510+ // section_number = 0x00
4511+ // last_section_number = 0x00
4512+ // one program follows:
4513+ // program_number = 0x0001
4514+ // reserved = b111
4515+ // program_map_PID = kPID_PMT (13 bits!)
4516+ // CRC = 0x????????
4517+
4518+ if (++pat_continuity_counter_ == 16)
4519+ pat_continuity_counter_ = 0;
4520+
4521+ uint8_t *ptr = packetDataStart;
4522+ *ptr++ = 0x47;
4523+ *ptr++ = 0x40;
4524+ *ptr++ = 0x00;
4525+ *ptr++ = 0x10 | pat_continuity_counter_;
4526+ *ptr++ = 0x00;
4527+
4528+ uint8_t *crcDataStart = ptr;
4529+ *ptr++ = 0x00;
4530+ *ptr++ = 0xb0;
4531+ *ptr++ = 0x0d;
4532+ *ptr++ = 0x00;
4533+ *ptr++ = 0x00;
4534+ *ptr++ = 0xc3;
4535+ *ptr++ = 0x00;
4536+ *ptr++ = 0x00;
4537+ *ptr++ = 0x00;
4538+ *ptr++ = 0x01;
4539+ *ptr++ = 0xe0 | (kPIDofPMT >> 8);
4540+ *ptr++ = kPIDofPMT & 0xff;
4541+
4542+ if (ptr - crcDataStart != 12)
4543+ MCS_FATAL("Invalid position for ptr");
4544+
4545+ uint32_t crc = ::htonl(CalcCrc32(crcDataStart, ptr - crcDataStart));
4546+ ::memcpy(ptr, &crc, 4);
4547+ ptr += 4;
4548+
4549+ size_t sizeLeft = packetDataStart + 188 - ptr;
4550+ ::memset(ptr, 0xff, sizeLeft);
4551+
4552+ packetDataStart += 188;
4553+
4554+ // Program Map (PMT):
4555+ // 0x47
4556+ // transport_error_indicator = b0
4557+ // payload_unit_start_indicator = b1
4558+ // transport_priority = b0
4559+ // PID = kPID_PMT (13 bits)
4560+ // transport_scrambling_control = b00
4561+ // adaptation_field_control = b01 (no adaptation field, payload only)
4562+ // continuity_counter = b????
4563+ // skip = 0x00
4564+ // -- payload follows
4565+ // table_id = 0x02
4566+ // section_syntax_indicator = b1
4567+ // must_be_zero = b0
4568+ // reserved = b11
4569+ // section_length = 0x???
4570+ // program_number = 0x0001
4571+ // reserved = b11
4572+ // version_number = b00001
4573+ // current_next_indicator = b1
4574+ // section_number = 0x00
4575+ // last_section_number = 0x00
4576+ // reserved = b111
4577+ // PCR_PID = kPCR_PID (13 bits)
4578+ // reserved = b1111
4579+ // program_info_length = 0x???
4580+ // program_info_descriptors follow
4581+ // one or more elementary stream descriptions follow:
4582+ // stream_type = 0x??
4583+ // reserved = b111
4584+ // elementary_PID = b? ???? ???? ???? (13 bits)
4585+ // reserved = b1111
4586+ // ES_info_length = 0x000
4587+ // CRC = 0x????????
4588+
4589+ if (++pmt_continuity_counter_ == 16)
4590+ pmt_continuity_counter_ = 0;
4591+
4592+ ptr = packetDataStart;
4593+
4594+ *ptr++ = 0x47;
4595+ *ptr++ = 0x40 | (kPIDofPMT >> 8);
4596+ *ptr++ = kPIDofPMT & 0xff;
4597+ *ptr++ = 0x10 | pmt_continuity_counter_;
4598+ *ptr++ = 0x00;
4599+
4600+ crcDataStart = ptr;
4601+ *ptr++ = 0x02;
4602+
4603+ *ptr++ = 0x00; // section_length to be filled in below.
4604+ *ptr++ = 0x00;
4605+
4606+ *ptr++ = 0x00;
4607+ *ptr++ = 0x01;
4608+ *ptr++ = 0xc3;
4609+ *ptr++ = 0x00;
4610+ *ptr++ = 0x00;
4611+ *ptr++ = 0xe0 | (kPIDofPCR >> 8);
4612+ *ptr++ = kPIDofPCR & 0xff;
4613+
4614+ size_t program_info_length = 0;
4615+ for (auto descriptor : program_info_descriptors_)
4616+ program_info_length += descriptor->Length();
4617+
4618+ if(program_info_length >= 0x400)
4619+ MCS_FATAL("Invalid length for program info");
4620+
4621+ *ptr++ = 0xf0 | (program_info_length >> 8);
4622+ *ptr++ = (program_info_length & 0xff);
4623+
4624+ for (auto descriptor : program_info_descriptors_) {
4625+ ::memcpy(ptr, descriptor->Data(), descriptor->Length());
4626+ ptr += descriptor->Length();
4627+ }
4628+
4629+ for (auto track : tracks_) {
4630+ // Make sure all the decriptors have been added.
4631+ track->Finalize();
4632+
4633+ *ptr++ = track->StreamType();
4634+ *ptr++ = 0xe0 | (track->PID() >> 8);
4635+ *ptr++ = track->PID() & 0xff;
4636+
4637+ auto descriptors = track->Descriptors();
4638+
4639+ size_t ES_info_length = 0;
4640+ for (auto descriptor : descriptors)
4641+ ES_info_length += descriptor->Length();
4642+
4643+ if (ES_info_length > 0xfff)
4644+ MCS_FATAL("Invalid ES length %d", ES_info_length);
4645+
4646+ *ptr++ = 0xf0 | (ES_info_length >> 8);
4647+ *ptr++ = (ES_info_length & 0xff);
4648+
4649+ for (auto descriptor : descriptors) {
4650+ memcpy(ptr, descriptor->Data(), descriptor->Length());
4651+ ptr += descriptor->Length();
4652+ }
4653+ }
4654+
4655+ size_t section_length = ptr - (crcDataStart + 3) + 4 /* CRC */;
4656+
4657+ crcDataStart[1] = 0xb0 | (section_length >> 8);
4658+ crcDataStart[2] = section_length & 0xff;
4659+
4660+ crc = ::htonl(CalcCrc32(crcDataStart, ptr - crcDataStart));
4661+ memcpy(ptr, &crc, 4);
4662+ ptr += 4;
4663+
4664+ sizeLeft = packetDataStart + 188 - ptr;
4665+ memset(ptr, 0xff, sizeLeft);
4666+
4667+ packetDataStart += 188;
4668+ }
4669+
4670+ if (flags & Flags::kEmitPCR) {
4671+ // PCR stream
4672+ // 0x47
4673+ // transport_error_indicator = b0
4674+ // payload_unit_start_indicator = b1
4675+ // transport_priority = b0
4676+ // PID = kPCR_PID (13 bits)
4677+ // transport_scrambling_control = b00
4678+ // adaptation_field_control = b10 (adaptation field only, no payload)
4679+ // continuity_counter = b0000 (does not increment)
4680+ // adaptation_field_length = 183
4681+ // discontinuity_indicator = b0
4682+ // random_access_indicator = b0
4683+ // elementary_stream_priority_indicator = b0
4684+ // PCR_flag = b1
4685+ // OPCR_flag = b0
4686+ // splicing_point_flag = b0
4687+ // transport_private_data_flag = b0
4688+ // adaptation_field_extension_flag = b0
4689+ // program_clock_reference_base = b?????????????????????????????????
4690+ // reserved = b111111
4691+ // program_clock_reference_extension = b?????????
4692+
4693+ int64_t nowUs = mcs::Utils::GetNowUs();
4694+ uint64_t PCR = nowUs * 27; // PCR based on a 27MHz clock
4695+ uint64_t PCR_base = PCR / 300;
4696+ uint32_t PCR_ext = PCR % 300;
4697+
4698+ uint8_t *ptr = packetDataStart;
4699+ *ptr++ = 0x47;
4700+ *ptr++ = 0x40 | (kPIDofPCR >> 8);
4701+ *ptr++ = kPIDofPCR & 0xff;
4702+ *ptr++ = 0x20;
4703+ *ptr++ = 0xb7; // adaptation_field_length
4704+ *ptr++ = 0x10;
4705+ *ptr++ = (PCR_base >> 25) & 0xff;
4706+ *ptr++ = (PCR_base >> 17) & 0xff;
4707+ *ptr++ = (PCR_base >> 9) & 0xff;
4708+ *ptr++ = ((PCR_base & 1) << 7) | 0x7e | ((PCR_ext >> 8) & 1);
4709+ *ptr++ = (PCR_ext & 0xff);
4710+
4711+ size_t sizeLeft = packetDataStart + 188 - ptr;
4712+ ::memset(ptr, 0xff, sizeLeft);
4713+
4714+ packetDataStart += 188;
4715+ }
4716+
4717+ // Adjust time to 90kHz
4718+ uint64_t PTS = (timeUs * 9ll) / 100ll;
4719+
4720+ if (PES_packet_length >= 65536) {
4721+ // This really should only happen for video.
4722+ if (!track->IsVideo())
4723+ MCS_FATAL("PES packet length too hight; should only happen for video (track %d mime %s)",
4724+ track_index, track->Format().mime);
4725+
4726+ MCS_WARNING("Reset PES packet length to 0");
4727+
4728+ // It's valid to set this to 0 for video according to the specs.
4729+ PES_packet_length = 0;
4730+ }
4731+
4732+ size_t sizeAvailableForPayload = 188 - 4 - 14 - numStuffingBytes;
4733+ if (PES_private_data_len > 0) {
4734+ sizeAvailableForPayload -= PES_private_data_len + 1;
4735+ }
4736+
4737+ size_t copy = access_unit->Length();
4738+
4739+ if (copy > sizeAvailableForPayload) {
4740+ copy = sizeAvailableForPayload;
4741+
4742+ if (alignPayload && copy > 16) {
4743+ copy -= (copy % 16);
4744+ }
4745+ }
4746+
4747+ size_t numPaddingBytes = sizeAvailableForPayload - copy;
4748+
4749+ uint8_t *ptr = packetDataStart;
4750+ *ptr++ = 0x47;
4751+ *ptr++ = 0x40 | (track->PID() >> 8);
4752+ *ptr++ = track->PID() & 0xff;
4753+
4754+ *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
4755+ | track->NextContinuityCounter();
4756+
4757+ if (numPaddingBytes > 0) {
4758+ *ptr++ = numPaddingBytes - 1;
4759+ if (numPaddingBytes >= 2) {
4760+ *ptr++ = 0x00;
4761+ ::memset(ptr, 0xff, numPaddingBytes - 2);
4762+ ptr += numPaddingBytes - 2;
4763+ }
4764+ }
4765+
4766+ *ptr++ = 0x00;
4767+ *ptr++ = 0x00;
4768+ *ptr++ = 0x01;
4769+ *ptr++ = track->StreamId();
4770+ *ptr++ = PES_packet_length >> 8;
4771+ *ptr++ = PES_packet_length & 0xff;
4772+ *ptr++ = 0x84;
4773+ *ptr++ = (PES_private_data_len > 0) ? 0x81 : 0x80;
4774+
4775+ size_t headerLength = 0x05 + numStuffingBytes;
4776+ if (PES_private_data_len > 0) {
4777+ headerLength += 1 + PES_private_data_len;
4778+ }
4779+
4780+ *ptr++ = headerLength;
4781+
4782+ *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
4783+ *ptr++ = (PTS >> 22) & 0xff;
4784+ *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1;
4785+ *ptr++ = (PTS >> 7) & 0xff;
4786+ *ptr++ = ((PTS & 0x7f) << 1) | 1;
4787+
4788+ if (PES_private_data_len > 0) {
4789+ *ptr++ = 0x8e; // PES_private_data_flag, reserved.
4790+ ::memcpy(ptr, PES_private_data, PES_private_data_len);
4791+ ptr += PES_private_data_len;
4792+ }
4793+
4794+ for (size_t i = 0; i < numStuffingBytes; ++i) {
4795+ *ptr++ = 0xff;
4796+ }
4797+
4798+ ::memcpy(ptr, access_unit->Data(), copy);
4799+ ptr += copy;
4800+
4801+ if (ptr != packetDataStart + 188)
4802+ MCS_FATAL("Invalid pointer %p", ptr);
4803+
4804+ packetDataStart += 188;
4805+
4806+ size_t offset = copy;
4807+ while (offset < access_unit->Length()) {
4808+ // for subsequent fragments of "buffer":
4809+ // 0x47
4810+ // transport_error_indicator = b0
4811+ // payload_unit_start_indicator = b0
4812+ // transport_priority = b0
4813+ // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
4814+ // transport_scrambling_control = b00
4815+ // adaptation_field_control = b??
4816+ // continuity_counter = b????
4817+ // the fragment of "buffer" follows.
4818+
4819+ size_t sizeAvailableForPayload = 188 - 4;
4820+
4821+ size_t copy = access_unit->Length() - offset;
4822+
4823+ if (copy > sizeAvailableForPayload) {
4824+ copy = sizeAvailableForPayload;
4825+
4826+ if (alignPayload && copy > 16) {
4827+ copy -= (copy % 16);
4828+ }
4829+ }
4830+
4831+ size_t numPaddingBytes = sizeAvailableForPayload - copy;
4832+
4833+ uint8_t *ptr = packetDataStart;
4834+ *ptr++ = 0x47;
4835+ *ptr++ = 0x00 | (track->PID() >> 8);
4836+ *ptr++ = track->PID() & 0xff;
4837+
4838+ *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
4839+ | track->NextContinuityCounter();
4840+
4841+ if (numPaddingBytes > 0) {
4842+ *ptr++ = numPaddingBytes - 1;
4843+ if (numPaddingBytes >= 2) {
4844+ *ptr++ = 0x00;
4845+ memset(ptr, 0xff, numPaddingBytes - 2);
4846+ ptr += numPaddingBytes - 2;
4847+ }
4848+ }
4849+
4850+ memcpy(ptr, access_unit->Data() + offset, copy);
4851+ ptr += copy;
4852+ if (ptr != packetDataStart + 188)
4853+ MCS_FATAL("Invalid pointer position %p", ptr);
4854+
4855+ offset += copy;
4856+ packetDataStart += 188;
4857+ }
4858+
4859+ if (packetDataStart != buffer->Data() + buffer->Length())
4860+ MCS_FATAL("Invalid packet start position");
4861+
4862+ *packets = buffer;
4863+
4864+#if 0
4865+ auto now = mcs::Utils::GetNowUs();
4866+ MCS_DEBUG("Buffer packtized after %lld ms (timestamp %lld now %lld)",
4867+ (now - buffer->Timestamp()) / 1000ll,
4868+ buffer->Timestamp(), now);
4869+#endif
4870+
4871+ return true;
4872+}
4873+
4874+void MPEGTSPacketizer::InitCrcTable() {
4875+ uint32_t poly = 0x04C11DB7;
4876+
4877+ for (int i = 0; i < 256; i++) {
4878+ uint32_t crc = i << 24;
4879+ for (int j = 0; j < 8; j++) {
4880+ crc = (crc << 1) ^ ((crc & 0x80000000) ? (poly) : 0);
4881+ }
4882+ crc_table_[i] = crc;
4883+ }
4884+}
4885+
4886+uint32_t MPEGTSPacketizer::CalcCrc32(const uint8_t *start, size_t size) const {
4887+ uint32_t crc = 0xFFFFFFFF;
4888+ const uint8_t *p;
4889+
4890+ for (p = start; p < start + size; ++p) {
4891+ crc = (crc << 8) ^ crc_table_[((crc >> 24) ^ *p) & 0xFF];
4892+ }
4893+
4894+ return crc;
4895+}
4896+
4897+} // namespace streaming
4898+} // namespace mcs
4899
4900=== added file 'src/mcs/streaming/mpegtspacketizer.h'
4901--- src/mcs/streaming/mpegtspacketizer.h 1970-01-01 00:00:00 +0000
4902+++ src/mcs/streaming/mpegtspacketizer.h 2016-02-25 12:47:02 +0000
4903@@ -0,0 +1,97 @@
4904+/*
4905+ * Copyright 2012, The Android Open Source Project
4906+ * Copyright (C) 2016 Canonical, Ltd.
4907+ *
4908+ * Licensed under the Apache License, Version 2.0 (the "License");
4909+ * you may not use this file except in compliance with the License.
4910+ * You may obtain a copy of the License at
4911+ *
4912+ * http://www.apache.org/licenses/LICENSE-2.0
4913+ *
4914+ * Unless required by applicable law or agreed to in writing, software
4915+ * distributed under the License is distributed on an "AS IS" BASIS,
4916+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4917+ * See the License for the specific language governing permissions and
4918+ * limitations under the License.
4919+ */
4920+
4921+#ifndef MCS_STREAMING_MPEGTSPACKETIZER_H_
4922+#define MCS_STREAMING_MPEGTSPACKETIZER_H_
4923+
4924+#include <memory>
4925+#include <vector>
4926+
4927+#include <mcs/video/buffer.h>
4928+
4929+namespace mcs {
4930+namespace streaming {
4931+
4932+class MPEGTSPacketizer {
4933+public:
4934+ typedef std::shared_ptr<MPEGTSPacketizer> Ptr;
4935+ typedef int TrackId;
4936+
4937+ enum Flags {
4938+ kEmitPATandPMT = 1,
4939+ kEmitPCR = 2,
4940+ kIsEncrypted = 4,
4941+ kPrependSPSandPPStoIDRFrames = 8,
4942+ };
4943+
4944+ struct TrackFormat {
4945+ public:
4946+ TrackFormat(const std::string &mime = "",
4947+ unsigned int profile_idc = 0,
4948+ unsigned int level_idc = 0,
4949+ unsigned int constraint_set = 0) :
4950+ mime(mime),
4951+ profile_idc(profile_idc),
4952+ level_idc(level_idc),
4953+ constraint_set(constraint_set) {
4954+ }
4955+ TrackFormat(const TrackFormat &other) :
4956+ mime(other.mime),
4957+ profile_idc(other.profile_idc),
4958+ level_idc(other.level_idc),
4959+ constraint_set(other.constraint_set) {
4960+ }
4961+
4962+ std::string mime;
4963+ unsigned int profile_idc;
4964+ unsigned int level_idc;
4965+ unsigned int constraint_set;
4966+ };
4967+
4968+ static Ptr Create();
4969+
4970+ ~MPEGTSPacketizer();
4971+
4972+ TrackId AddTrack(const TrackFormat &format);
4973+
4974+ void SubmitCSD(TrackId track_index, const video::Buffer::Ptr &buffer);
4975+
4976+ bool Packetize(TrackId track_index, const video::Buffer::Ptr &access_unit,
4977+ video::Buffer::Ptr *packets, int flags = 0);
4978+
4979+private:
4980+ MPEGTSPacketizer();
4981+
4982+private:
4983+ void InitCrcTable();
4984+ uint32_t CalcCrc32(const uint8_t *start, size_t size) const;
4985+
4986+private:
4987+ struct Track;
4988+
4989+private:
4990+ unsigned int pat_continuity_counter_;
4991+ unsigned int pmt_continuity_counter_;
4992+ uint32_t crc_table_[256];
4993+ std::vector<std::shared_ptr<Track>> tracks_;
4994+ std::vector<video::Buffer::Ptr> program_info_descriptors_;
4995+};
4996+
4997+} // namespace streaming
4998+} // namespace mcs
4999+
5000+#endif
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: