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
=== added file '.gitignore'
--- .gitignore 1970-01-01 00:00:00 +0000
+++ .gitignore 2016-02-25 12:47:02 +0000
@@ -0,0 +1,1 @@
1build*/
02
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-01-12 06:54:24 +0000
+++ CMakeLists.txt 2016-02-25 12:47:02 +0000
@@ -54,7 +54,7 @@
5454
55include(cmake/FindReadline.cmake)55include(cmake/FindReadline.cmake)
5656
57find_package(Boost COMPONENTS filesystem log system thread)57find_package(Boost COMPONENTS filesystem log system thread program_options)
58find_package(PkgConfig)58find_package(PkgConfig)
59find_package(Threads)59find_package(Threads)
6060
@@ -62,7 +62,19 @@
62pkg_check_modules(GIO REQUIRED gio-2.0)62pkg_check_modules(GIO REQUIRED gio-2.0)
63pkg_check_modules(GIO-UNIX REQUIRED gio-unix-2.0)63pkg_check_modules(GIO-UNIX REQUIRED gio-unix-2.0)
64pkg_check_modules(GST REQUIRED gstreamer-1.0)64pkg_check_modules(GST REQUIRED gstreamer-1.0)
65pkg_check_modules(GST_APP REQUIRED gstreamer-app-1.0)
65pkg_check_modules(WDS REQUIRED wds)66pkg_check_modules(WDS REQUIRED wds)
67# FIXME for the time being mir is required to do proper hardware
68# encoding on Android platforms. This will be refactored at some
69# point to be abstracted by gstreamer completely or made optional.
70pkg_check_modules(MIRCLIENT REQUIRED mirclient)
71# Same as mentioned above applies for the hybris and android
72# things below.
73pkg_check_modules(HYBRIS_MEDIA REQUIRED libmedia)
74pkg_check_modules(ANDROID_HEADERS REQUIRED android-headers)
75pkg_check_modules(EGL REQUIRED egl)
76pkg_check_modules(GLESV2 REQUIRED glesv2)
77add_definitions(-DMESA_EGL_NO_X11_HEADERS)
6678
67# Build with system gmock and embedded gtest79# Build with system gmock and embedded gtest
68set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory")80set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory")
@@ -78,3 +90,4 @@
78add_subdirectory(conf)90add_subdirectory(conf)
79add_subdirectory(src)91add_subdirectory(src)
80add_subdirectory(tests)92add_subdirectory(tests)
93add_subdirectory(tools)
8194
=== added file 'cmake/LinuxCrossCompile.cmake'
--- cmake/LinuxCrossCompile.cmake 1970-01-01 00:00:00 +0000
+++ cmake/LinuxCrossCompile.cmake 2016-02-25 12:47:02 +0000
@@ -0,0 +1,43 @@
1set(CMAKE_SYSTEM_NAME Linux)
2set(CMAKE_SYSTEM_VERSION 1)
3
4set(AC_NDK_PATH $ENV{AC_NDK_PATH} CACHE STRING "path of mir android bundle")
5
6if (NOT DEFINED AC_TARGET_MACHINE)
7 set(AC_TARGET_MACHINE $ENV{AC_TARGET_MACHINE} CACHE STRING "target machine")
8endif()
9if (NOT DEFINED AC_GCC_VARIANT)
10 set(AC_GCC_VARIANT $ENV{AC_GCC_VARIANT} CACHE STRING "gcc variant required")
11endif()
12
13set(CMAKE_C_COMPILER /usr/bin/${AC_TARGET_MACHINE}-gcc${AC_GCC_VARIANT})
14set(CMAKE_CXX_COMPILER /usr/bin/${AC_TARGET_MACHINE}-g++${AC_GCC_VARIANT})
15
16# where to look to find dependencies in the target environment
17set(CMAKE_FIND_ROOT_PATH "${AC_NDK_PATH}")
18
19#treat the chroot's includes as system includes
20include_directories(SYSTEM "${AC_NDK_PATH}/usr/include" "${AC_NDK_PATH}/usr/include/${AC_TARGET_MACHINE}")
21list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${AC_NDK_PATH}/usr/include" "${AC_NDK_PATH}/usr/include/${AC_TARGET_MACHINE}" )
22
23# Add the chroot libraries as system libraries
24list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
25 "${AC_NDK_PATH}/lib"
26 "${AC_NDK_PATH}/lib/${AC_TARGET_MACHINE}"
27 "${AC_NDK_PATH}/usr/lib"
28 "${AC_NDK_PATH}/usr/lib/${AC_TARGET_MACHINE}"
29)
30
31set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
32set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
33set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG "-Wl,-rpath-link,")
34set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG "-Wl,-rpath-link,")
35set(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}")
36
37set(ENV{PKG_CONFIG_PATH} "${AC_NDK_PATH}/usr/lib/pkgconfig:${AC_NDK_PATH}/usr/lib/${AC_TARGET_MACHINE}/pkgconfig")
38set(ENV{PKG_CONFIG_SYSROOT_DIR} "${AC_NDK_PATH}")
39
40#use only the cross compile system
41set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
42set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
43set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
044
=== removed file 'conf/dhcpd.conf'
--- conf/dhcpd.conf 2016-01-16 13:02:21 +0000
+++ conf/dhcpd.conf 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
1subnet 192.168.7.0 netmask 255.255.255.0 {
2 range 192.168.7.5 192.168.7.10;
3 option subnet-mask 255.255.255.0;
4 option broadcast-address 192.168.7.255;
5}
60
=== added file 'cross-compile-chroot.sh'
--- cross-compile-chroot.sh 1970-01-01 00:00:00 +0000
+++ cross-compile-chroot.sh 2016-02-25 12:47:02 +0000
@@ -0,0 +1,163 @@
1#!/bin/bash
2# build script to compile Aethercast for armhf devices
3#
4set -e
5
6usage() {
7 echo "usage: $(basename $0) [-a <arch>] [-c] [-h] [-d <dist>] [-u]"
8 echo " -a <arch> Specify target architecture (armhf/arm64/powerpc/ppc64el/amd64/i386/host)"
9 echo " -c Clean before building"
10 echo " -d <dist> Select the distribution to build for (vivid/wily/xenial)"
11 echo " -h This message"
12 echo " -u Update partial chroot directory"
13}
14
15clean_build_dir() {
16 rm -rf ${1}
17 mkdir ${1}
18}
19
20# Default to a dist-agnostic directory name so as to not break Jenkins right now
21BUILD_DIR=build-android-arm
22NUM_JOBS=$(( $(grep -c ^processor /proc/cpuinfo) + 1 ))
23_do_update_chroot=0
24
25# Default to vivid as we don't seem to have any working wily devices right now
26dist=vivid
27clean=0
28update_build_dir=0
29
30target_arch=armhf
31
32while getopts "a:cd:hu" OPTNAME
33do
34 case $OPTNAME in
35 a )
36 target_arch=${OPTARG}
37 update_build_dir=1
38 ;;
39 c )
40 clean=1
41 ;;
42 d )
43 dist=${OPTARG}
44 update_build_dir=1
45 ;;
46 u )
47 _do_update_chroot=1
48 ;;
49 h )
50 usage
51 exit 0
52 ;;
53 : )
54 echo "Parameter -${OPTARG} needs an argument"
55 usage
56 exit 1;
57 ;;
58 * )
59 echo "invalid option specified"
60 usage
61 exit 1
62 ;;
63 esac
64done
65
66shift $((${OPTIND}-1))
67
68if [ "${target_arch}" = "host" ]; then
69 target_arch=`dpkg-architecture -qDEB_HOST_ARCH`
70fi
71
72if [ ${clean} -ne 0 ]; then
73 clean_build_dir ${BUILD_DIR}
74fi
75
76if [ ${update_build_dir} -eq 1 ]; then
77 BUILD_DIR=build-${target_arch}-${dist}
78fi
79
80if [ "${AC_NDK_PATH}" = "" ]; then
81 export AC_NDK_PATH=~/.cache/aethercast-${target_arch}-chroot-${dist}
82fi
83
84if [ ! -d ${AC_NDK_PATH} ]; then
85 echo "no partial chroot dir detected. attempting to create one"
86 _do_update_chroot=1
87fi
88
89if [ ! -d ${BUILD_DIR} ]; then
90 mkdir ${BUILD_DIR}
91fi
92
93echo "Building for distro: $dist"
94echo "Using AC_NDK_PATH: ${AC_NDK_PATH}"
95
96additional_repositories=
97if [ ${dist} == "vivid" ] ; then
98 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"
99fi
100
101gcc_variant=
102if [ "${dist}" = "vivid" ]; then
103 gcc_variant=-4.9
104fi
105
106case ${target_arch} in
107 armhf )
108 target_machine=arm-linux-gnueabihf
109 ;;
110 amd64 )
111 target_machine=x86_64-linux-gnu
112 ;;
113 i386 )
114 target_machine=i386-linux-gnu
115 ;;
116 arm64 )
117 target_machine=aarch64-linux-gnu
118 ;;
119 ppc64el )
120 target_machine=powerpc64le-linux-gnu
121 ;;
122 powerpc )
123 target_machine=powerpc-linux-gnu
124 ;;
125 * )
126 # A good guess (assuming you have dpkg-architecture)
127 target_machine=`dpkg-architecture -A${target_arch} -qDEB_HOST_MULTIARCH` || {
128 echo "Unknown architecture ${target_arch}"
129 usage
130 exit 1
131 }
132 ;;
133esac
134
135echo "Target architecture: ${target_arch}"
136echo "Target machine: ${target_machine}"
137
138if [ ${_do_update_chroot} -eq 1 ] ; then
139 pushd scripts > /dev/null
140 ./setup-partial-armhf-chroot.sh -d ${dist} -a ${target_arch} ${additional_repositories} ${AC_NDK_PATH}
141 popd > /dev/null
142 # force a clean build after an update, since CMake cache maybe out of date
143 clean_build_dir ${BUILD_DIR}
144fi
145
146pushd ${BUILD_DIR} > /dev/null
147
148 export PKG_CONFIG_PATH="${AC_NDK_PATH}/usr/lib/pkgconfig:${AC_NDK_PATH}/usr/lib/${target_machine}/pkgconfig"
149 export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
150 export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
151 export PKG_CONFIG_SYSROOT_DIR=$AC_NDK_PATH
152 export PKG_CONFIG_EXECUTABLE=`which pkg-config`
153 export AC_TARGET_MACHINE=${target_machine}
154 export AC_GCC_VARIANT=${gcc_variant}
155 echo "Using PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
156 echo "Using PKG_CONFIG_EXECUTABLE: $PKG_CONFIG_EXECUTABLE"
157 cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake \
158 -DCMAKE_BUILD_TYPE=debug \
159 ..
160
161 make -j${NUM_JOBS} $@
162
163popd > /dev/null
0164
=== added file 'data/fi.w1.wpa_supplicant1.xml'
--- data/fi.w1.wpa_supplicant1.xml 1970-01-01 00:00:00 +0000
+++ data/fi.w1.wpa_supplicant1.xml 2016-02-25 12:47:02 +0000
@@ -0,0 +1,112 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="fi.w1.wpa_supplicant1">
5 <method name="CreateInterface">
6 <arg name="args" type="a{sv}" direction="in"/>
7 <arg name="path" type="o" direction="out"/>
8 </method>
9 <signal name="InterfaceAdded">
10 <arg name="path" type="o"/>
11 <arg name="properties" type="a{sv}"/>
12 </signal>
13 <signal name="InterfaceRemoved">
14 <arg name="path" type="o"/>
15 </signal>
16 <property name="Interfaces" type="ao" access="read"/>
17 <property name="Capabilities" type="as" access="read"/>
18 <property name="WFDIEs" type="ay" access="readwrite">
19 <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
20 </property>
21 </interface>
22 <interface name="fi.w1.wpa_supplicant1.Interface">
23 <method name="SendDriverCommand">
24 <arg name="cmd" type="s" direction="in"/>
25 </method>
26 <property name="Capabilities" type="a{sv}" access="read"/>
27 <property name="State" type="s" access="read"/>
28 <property name="Ifname" type="s" access="read"/>
29 <property name="Driver" type="s" access="read"/>
30 </interface>
31 <interface name="fi.w1.wpa_supplicant1.Interface.P2PDevice">
32 <method name="Find">
33 <arg name="args" type="a{sv}" direction="in"/>
34 </method>
35 <method name="StopFind"/>
36 <method name="ExtendedListen">
37 <arg name="args" type="a{sv}" direction="in"/>
38 </method>
39 <method name="Connect">
40 <arg name="args" type="a{sv}" direction="in"/>
41 <arg name="group" type="s" direction="out"/>
42 </method>
43 <method name="Cancel"/>
44 <method name="Disconnect"/>
45 <method name="Flush"/>
46 <signal name="DeviceFound">
47 <arg name="path" type="o"/>
48 </signal>
49 <signal name="DeviceLost">
50 <arg name="path" type="o"/>
51 </signal>
52 <signal name="FindStopped"/>
53 <signal name="GONegotiationSuccess">
54 <arg name="properties" type="a{sv}"/>
55 </signal>
56 <signal name="GONegotiationFailure">
57 <arg name="properties" type="a{sv}"/>
58 </signal>
59 <signal name="GroupStarted">
60 <arg name="properties" type="a{sv}"/>
61 </signal>
62 <signal name="GroupFinished">
63 <arg name="properties" type="a{sv}"/>
64 </signal>
65 <signal name="GroupFormationFailure">
66 <arg name="reason" type="s"/>
67 </signal>
68 <signal name="GONegotiationRequest">
69 <arg name="path" type="o"/>
70 <arg name="dev_passwd_id" type="i"/>
71 </signal>
72 <property name="P2PDeviceConfig" type="a{sv}" access="readwrite"/>
73 <property name="Peers" type="ao" access="read"/>
74 </interface>
75 <interface name="fi.w1.wpa_supplicant1.Peer">
76 <property name="DeviceName" type="s" access="read"/>
77 <property name="Manufacturer" type="s" access="read"/>
78 <property name="ModelName" type="s" access="read"/>
79 <property name="ModelNumber" type="s" access="read"/>
80 <property name="SerialNumber" type="s" access="read"/>
81 <property name="PrimaryDeviceType" type="ay" access="read"/>
82 <property name="config_method" type="q" access="read"/>
83 <property name="level" type="i" access="read"/>
84 <property name="devicecapability" type="y" access="read"/>
85 <property name="groupcapability" type="y" access="read"/>
86 <property name="SecondaryDeviceTypes" type="aay" access="read"/>
87 <property name="VendorExtension" type="aay" access="read"/>
88 <property name="IEs" type="ay" access="read"/>
89 <property name="DeviceAddress" type="ay" access="read">
90 <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
91 </property>
92 <property name="Groups" type="ao" access="read"/>
93 </interface>
94 <interface name="fi.w1.wpa_supplicant1.Group">
95 <property name="Members" type="s" access="read"/>
96 <property name="Group" type="o" access="read"/>
97 <property name="Role" type="s" access="read"/>
98 <property name="SSID" type="ay" access="read"/>
99 <property name="BSSID" type="ay" access="read"/>
100 <property name="Frequency" type="q" access="read"/>
101 <property name="Passphrase" type="s" access="read"/>
102 <property name="PSK" type="ay" access="read"/>
103 <property name="WPSVendorExtensions" type="aay" access="read"/>
104 <signal name="PeerJoined">
105 <arg name="peer" type="o"/>
106 </signal>
107 <signal name="PeerDisconnected">
108 <arg name="peer" type="o"/>
109 </signal>
110 </interface>
111</node>
112
0113
=== removed file 'data/fi.w1.wpa_supplicant1.xml'
--- data/fi.w1.wpa_supplicant1.xml 2016-01-17 18:42:56 +0000
+++ data/fi.w1.wpa_supplicant1.xml 1970-01-01 00:00:00 +0000
@@ -1,109 +0,0 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="fi.w1.wpa_supplicant1">
5 <method name="CreateInterface">
6 <arg name="args" type="a{sv}" direction="in"/>
7 <arg name="path" type="o" direction="out"/>
8 </method>
9 <signal name="InterfaceAdded">
10 <arg name="path" type="o"/>
11 <arg name="properties" type="a{sv}"/>
12 </signal>
13 <signal name="InterfaceRemoved">
14 <arg name="path" type="o"/>
15 </signal>
16 <property name="Interfaces" type="ao" access="read"/>
17 <property name="Capabilities" type="as" access="read"/>
18 <property name="WFDIEs" type="ay" access="readwrite">
19 <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
20 </property>
21 </interface>
22 <interface name="fi.w1.wpa_supplicant1.Interface">
23 <property name="Capabilities" type="a{sv}" access="read"/>
24 <property name="State" type="s" access="read"/>
25 <property name="Ifname" type="s" access="read"/>
26 <property name="Driver" type="s" access="read"/>
27 </interface>
28 <interface name="fi.w1.wpa_supplicant1.Interface.P2PDevice">
29 <method name="Find">
30 <arg name="args" type="a{sv}" direction="in"/>
31 </method>
32 <method name="StopFind"/>
33 <method name="ExtendedListen">
34 <arg name="args" type="a{sv}" direction="in"/>
35 </method>
36 <method name="Connect">
37 <arg name="args" type="a{sv}" direction="in"/>
38 <arg name="group" type="s" direction="out"/>
39 </method>
40 <method name="Cancel"/>
41 <method name="Disconnect"/>
42 <method name="Flush"/>
43 <signal name="DeviceFound">
44 <arg name="path" type="o"/>
45 </signal>
46 <signal name="DeviceLost">
47 <arg name="path" type="o"/>
48 </signal>
49 <signal name="FindStopped"/>
50 <signal name="GONegotiationSuccess">
51 <arg name="properties" type="a{sv}"/>
52 </signal>
53 <signal name="GONegotiationFailure">
54 <arg name="properties" type="a{sv}"/>
55 </signal>
56 <signal name="GroupStarted">
57 <arg name="properties" type="a{sv}"/>
58 </signal>
59 <signal name="GroupFinished">
60 <arg name="properties" type="a{sv}"/>
61 </signal>
62 <signal name="GroupFormationFailure">
63 <arg name="reason" type="s"/>
64 </signal>
65 <signal name="GONegotiationRequest">
66 <arg name="path" type="o"/>
67 <arg name="dev_passwd_id" type="i"/>
68 </signal>
69 <property name="P2PDeviceConfig" type="a{sv}" access="readwrite"/>
70 <property name="Peers" type="ao" access="read"/>
71 </interface>
72 <interface name="fi.w1.wpa_supplicant1.Peer">
73 <property name="DeviceName" type="s" access="read"/>
74 <property name="Manufacturer" type="s" access="read"/>
75 <property name="ModelName" type="s" access="read"/>
76 <property name="ModelNumber" type="s" access="read"/>
77 <property name="SerialNumber" type="s" access="read"/>
78 <property name="PrimaryDeviceType" type="ay" access="read"/>
79 <property name="config_method" type="q" access="read"/>
80 <property name="level" type="i" access="read"/>
81 <property name="devicecapability" type="y" access="read"/>
82 <property name="groupcapability" type="y" access="read"/>
83 <property name="SecondaryDeviceTypes" type="aay" access="read"/>
84 <property name="VendorExtension" type="aay" access="read"/>
85 <property name="IEs" type="ay" access="read"/>
86 <property name="DeviceAddress" type="ay" access="read">
87 <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
88 </property>
89 <property name="Groups" type="ao" access="read"/>
90 </interface>
91 <interface name="fi.w1.wpa_supplicant1.Group">
92 <property name="Members" type="s" access="read"/>
93 <property name="Group" type="o" access="read"/>
94 <property name="Role" type="s" access="read"/>
95 <property name="SSID" type="ay" access="read"/>
96 <property name="BSSID" type="ay" access="read"/>
97 <property name="Frequency" type="q" access="read"/>
98 <property name="Passphrase" type="s" access="read"/>
99 <property name="PSK" type="ay" access="read"/>
100 <property name="WPSVendorExtensions" type="aay" access="read"/>
101 <signal name="PeerJoined">
102 <arg name="peer" type="o"/>
103 </signal>
104 <signal name="PeerDisconnected">
105 <arg name="peer" type="o"/>
106 </signal>
107 </interface>
108</node>
109
1100
=== modified file 'data/org.aethercast.xml'
--- data/org.aethercast.xml 2015-12-10 17:13:50 +0000
+++ data/org.aethercast.xml 2016-02-25 12:47:02 +0000
@@ -9,6 +9,8 @@
9 <arg name="path" type="o" direction="in"/>9 <arg name="path" type="o" direction="in"/>
10 </method>10 </method>
11 <method name="Scan"/>11 <method name="Scan"/>
12 <!-- FIXME just for demo purposes. Don't use this method. -->
13 <method name="DisconnectAll"/>
12 <property name="State" type="s" access="read"/>14 <property name="State" type="s" access="read"/>
13 <property name="Capabilities" type="as" access="read"/>15 <property name="Capabilities" type="as" access="read"/>
14 <property name="Scanning" type="b" access="read"/>16 <property name="Scanning" type="b" access="read"/>
1517
=== added file 'debian/aethercast-tools.install'
--- debian/aethercast-tools.install 1970-01-01 00:00:00 +0000
+++ debian/aethercast-tools.install 2016-02-25 12:47:02 +0000
@@ -0,0 +1,1 @@
1usr/bin/mirscreencast_to_stream
02
=== removed file 'debian/aethercast.install'
--- debian/aethercast.install 2016-01-17 14:08:15 +0000
+++ debian/aethercast.install 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1debian/usr.sbin.aethercast /etc/apparmor.d/dhcpd.d/
20
=== modified file 'debian/control'
--- debian/control 2016-01-21 11:13:32 +0000
+++ debian/control 2016-02-25 12:47:02 +0000
@@ -3,24 +3,31 @@
3Priority: optional3Priority: optional
4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
5XSBC-Original-Maintainer: Simon Fels <simon.fels@canonical.com>5XSBC-Original-Maintainer: Simon Fels <simon.fels@canonical.com>
6Build-Depends: cmake,6Build-Depends: android-headers-19 (>= 23),
7 cmake,
7 debhelper (>= 9),8 debhelper (>= 9),
9 dh-apparmor,
8 dbus,10 dbus,
9 google-mock,11 google-mock,
10 libboost-dev,12 libboost-dev,
11 libboost-filesystem-dev,13 libboost-filesystem-dev,
12 libboost-log-dev,14 libboost-log-dev,
13 libboost-iostreams-dev,15 libboost-iostreams-dev,
16 libboost-program-options-dev,
14 libboost-system-dev,17 libboost-system-dev,
15# boost log needs exactly one symbol from boost-thread for resolving18# boost log needs exactly one symbol from boost-thread for resolving
16# thread-specific storage locations.19# thread-specific storage locations.
17 libboost-thread-dev,20 libboost-thread-dev,
18 libglib2.0-dev,21 libglib2.0-dev,
19 libgstreamer1.0-dev,22 libgstreamer1.0-dev,
23 libgstreamer-plugins-base1.0-dev,
20 libgtest-dev,24 libgtest-dev,
25 libhybris-dev,
26 libmedia-dev,
21 libreadline-dev,27 libreadline-dev,
22 libreadline6-dev,28 libreadline6-dev,
23 libwds-dev29 libwds-dev,
30 pkg-config
24Standards-Version: 3.9.431Standards-Version: 3.9.4
25Homepage: http://launchpad.net/aethercast32Homepage: http://launchpad.net/aethercast
26# If you aren't a member of ~phablet-team but need to upload packaging changes,33# If you aren't a member of ~phablet-team but need to upload packaging changes,
@@ -29,9 +36,10 @@
29Vcs-Browser: http://bazaar.launchpad.net/aethercast/trunk/files36Vcs-Browser: http://bazaar.launchpad.net/aethercast/trunk/files
3037
31Package: aethercast38Package: aethercast
32Architecture: any39Architecture: i386 amd64 armhf
33Depends: ${misc:Depends},40Depends: ${misc:Depends},
34 ${shlibs:Depends},41 ${shlibs:Depends},
42 aethercast-tools,
35 isc-dhcp-server,43 isc-dhcp-server,
36 isc-dhcp-client,44 isc-dhcp-client,
37 wpasupplicant45 wpasupplicant
@@ -39,3 +47,18 @@
39 A management service for remote displays which it can stream the47 A management service for remote displays which it can stream the
40 current screen content to. It will support multiple approaches48 current screen content to. It will support multiple approaches
41 for this like Miracast.49 for this like Miracast.
50
51Package: aethercast-tools
52Architecture: i386 amd64 armhf
53Depends: ${misc:Depends},
54 ${shlibs:Depends},
55 isc-dhcp-server,
56 isc-dhcp-client,
57 wpasupplicant
58Description: Tools for the display casting service
59 A management service for remote displays which it can stream the
60 current screen content to. It will support multiple approaches
61 for this like Miracast.
62 .
63 This package contains small utilities helping to work with the
64 display streaming stack.
4265
=== modified file 'debian/rules'
--- debian/rules 2016-01-17 14:01:37 +0000
+++ debian/rules 2016-02-25 12:47:02 +0000
@@ -20,3 +20,7 @@
2020
21override_dh_auto_test:21override_dh_auto_test:
22 # disable22 # disable
23
24override_dh_install:
25 dh_install
26 dh_apparmor -paethercast --profile-name=usr.sbin.dhcpd
2327
=== modified file 'debian/usr.sbin.aethercast'
--- debian/usr.sbin.aethercast 2016-01-30 12:33:55 +0000
+++ debian/usr.sbin.aethercast 2016-02-25 12:47:02 +0000
@@ -1,11 +1,15 @@
1# vim:syntax=apparmor1# vim:syntax=apparmor
22
3 # Allow aethercast to start dhcpd with its own configuration3# Work around bug:
4 # file it needs to provide DHCP for groups it manages through4# https://bugs.launchpad.net/ubuntu/+source/isc-dhcp/+bug/1186662
5 # WiFi Direct. This need to stay as long as NetworkManager does5capability dac_override,
6 # not has support for WiFi Direct and aethercast is using that.6
7 /etc/aethercast/dhcpd.conf r,7# Allow aethercast to start dhcpd with its own configuration
8 # In addition aethercast will also point dhcpd to a private8# file it needs to provide DHCP for groups it manages through
9 # lease/pid file9# WiFi Direct. This need to stay as long as NetworkManager does
10 /{,var/}run/aethercast/dhcpd*.leases* lrw,10# not has support for WiFi Direct and aethercast is using that.
11 /{,var/}run/aethercast/dhcpd*.pid lrw,11/etc/aethercast/dhcpd.conf r,
12# In addition aethercast will also point dhcpd to a private
13# lease/pid file
14/{,var/}run/aethercast/dhcpd*.leases lrw,
15/{,var/}run/aethercast/dhcpd*.pid lrw,
1216
=== added directory 'scripts'
=== added file 'scripts/setup-partial-armhf-chroot.sh'
--- scripts/setup-partial-armhf-chroot.sh 1970-01-01 00:00:00 +0000
+++ scripts/setup-partial-armhf-chroot.sh 2016-02-25 12:47:02 +0000
@@ -0,0 +1,155 @@
1#!/bin/bash
2#
3# TODO: Rename this file without "armhf" when it's safe to do so.
4#
5
6set -e
7
8name=${0}
9
10usage() {
11 echo "Usage: ${name} [options] mychroot-dir"
12 echo "options:"
13 echo " -a arch Select architecture, i.e. armhf, arm64, ppc... Default is armhf"
14 echo " -d dist Select distribution, i.e. vivid, wily. Default is vivid"
15 echo " -r rep Select an additional repository for bootstrap. Default is none"
16 echo
17 echo "please supply at least a directory to create partial chroot in. (eg, ./setup-partial-armhf-chroot.sh mychroot-dir)"
18}
19
20# Default to vivid as we don't seem to have any working wily devices right now.
21# Also Jenkins expects this script to default to vivid (TODO: update CI?)
22arch=armhf
23dist=vivid
24sourceid=0
25repositories=
26sources=
27
28while getopts a:d:r:h opt; do
29 case $opt in
30 a)
31 arch=$OPTARG
32 ;;
33 d)
34 dist=$OPTARG
35 ;;
36 r)
37 repositories="$repositories $OPTARG"
38 ((++sourceid))
39 sources="$sources source$sourceid"
40 ;;
41 :)
42 echo "Option -$OPTARG requires an argument"
43 usage
44 exit 1
45 ;;
46 h)
47 usage
48 exit 0
49 ;;
50 \?)
51 echo "Invalid option: -$OPTARG"
52 usage
53 exit 1
54 ;;
55 esac
56done
57
58shift $((OPTIND-1))
59
60if [ -z ${1} ]; then
61 usage
62 exit 1
63fi
64
65directory=${1}
66echo "creating phablet-compatible $arch partial chroot for aethercast compilation in directory ${directory}"
67
68if [ ! -d ${directory} ]; then
69 mkdir -p ${directory}
70fi
71
72DEBCONTROL=$(pwd)/../debian/control
73
74pushd ${directory} > /dev/null
75
76# Empty dpkg status file, so that ALL dependencies are listed with dpkg-checkbuilddeps
77echo "" > status
78
79# Manual error code checking is needed for dpkg-checkbuilddeps
80set +e
81
82# Parse dependencies from debian/control
83# dpkg-checkbuilddeps returns non-zero when dependencies are not met and the list is sent to stderr
84builddeps=$(dpkg-checkbuilddeps -a ${arch} --admindir=. ${DEBCONTROL} 2>&1 )
85if [ $? -eq 0 ] ; then
86 exit 0
87fi
88echo "${builddeps}"
89
90# now turn exit on error option
91set -e
92
93# Sanitize dependencies list for submission to multistrap
94# build-essential is not needed as we are cross-compiling
95builddeps=$(echo ${builddeps} | sed -e 's/dpkg-checkbuilddeps://g' \
96 -e 's/error://g' \
97 -e 's/Unmet build dependencies://g' \
98 -e 's/build-essential:native//g')
99builddeps=$(echo ${builddeps} | sed 's/([^)]*)//g')
100builddeps=$(echo ${builddeps} | sed -e 's/abi-compliance-checker//g')
101builddeps=$(echo ${builddeps} | sed -e 's/multistrap//g')
102
103case ${arch} in
104 amd64 | i386 )
105 source_url=http://archive.ubuntu.com/ubuntu
106 ;;
107 * )
108 source_url=http://ports.ubuntu.com/ubuntu-ports
109 ;;
110esac
111
112echo "[General]
113arch=${arch}
114directory=${directory}
115unpack=false
116noauth=true
117bootstrap=Ubuntu ${sources}
118
119[Ubuntu]
120packages=${builddeps}
121source=${source_url}
122suite=${dist}
123" > mstrap.conf
124
125sourceid=0
126for x in ${repositories};
127do
128 ((++sourceid))
129 echo "[source${sourceid}]
130source=${x}
131suite=${dist}
132" >> mstrap.conf
133done
134
135multistrap -f mstrap.conf
136
137rm -f var/cache/apt/archives/lock
138
139# Remove libc libraries that confuse the cross-compiler
140rm -f var/cache/apt/archives/libc-dev*.deb
141rm -f var/cache/apt/archives/libc6*.deb
142
143for deb in var/cache/apt/archives/* ; do
144 if [ ! -d ${deb} ] ; then
145 echo "unpacking: ${deb}"
146 dpkg -x ${deb} .
147 fi
148done
149
150# Fix up symlinks which asssumed the usual root path
151for broken_symlink in $(find . -name \*.so -type l -xtype l) ; do
152 ln -sf $(pwd)$(readlink ${broken_symlink}) ${broken_symlink}
153done
154
155popd > /dev/null
0156
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2016-01-21 13:25:31 +0000
+++ src/CMakeLists.txt 2016-02-25 12:47:02 +0000
@@ -27,15 +27,17 @@
27configure_file(w11tng/config.h.in w11tng/config.h @ONLY)27configure_file(w11tng/config.h.in w11tng/config.h @ONLY)
2828
29set(HEADERS29set(HEADERS
30 mcs/ip_v4_address.h30 mcs/ip_v4_address.h
31 mcs/keep_alive.h31 mcs/keep_alive.h
32 mcs/mac_address.h32 mcs/mac_address.h
33 mcs/types.h33 mcs/types.h
34 mcs/shared_gobject.h34 mcs/shared_gobject.h
35 mcs/keep_alive.h35 mcs/keep_alive.h
3636 mcs/config.h
37 mcs/config.h37
38 w11tng/config.h38 mcs/gl/common.h
39
40 w11tng/config.h
39)41)
4042
41set(SOURCES43set(SOURCES
@@ -43,11 +45,11 @@
43 mcs/networkutils.cpp45 mcs/networkutils.cpp
44 mcs/mediamanagerfactory.cpp46 mcs/mediamanagerfactory.cpp
45 mcs/basesourcemediamanager.cpp47 mcs/basesourcemediamanager.cpp
48 mcs/initgstreameronce.cpp
46 mcs/gstsourcemediamanager.cpp49 mcs/gstsourcemediamanager.cpp
47 mcs/testsourcemediamanager.cpp50 mcs/testsourcemediamanager.cpp
48 mcs/x11sourcemediamanager.cpp51 mcs/x11sourcemediamanager.cpp
49 mcs/logger.cpp52 mcs/logger.cpp
50 mcs/mirsourcemediamanager.cpp
51 mcs/forwardingmiracastcontroller.cpp53 mcs/forwardingmiracastcontroller.cpp
52 mcs/forwardingnetworkdevice.cpp54 mcs/forwardingnetworkdevice.cpp
53 mcs/miracastcontroller.cpp55 mcs/miracastcontroller.cpp
@@ -58,11 +60,39 @@
58 mcs/networkmanager.cpp60 mcs/networkmanager.cpp
59 mcs/networkmanagerfactory.cpp61 mcs/networkmanagerfactory.cpp
60 mcs/networkdevice.cpp62 mcs/networkdevice.cpp
6163 mcs/x264.cpp
62 ${CMAKE_CURRENT_BINARY_DIR}/mcs/aethercastinterface.c64 ${CMAKE_CURRENT_BINARY_DIR}/mcs/aethercastinterface.c
63 mcs/dbushelpers.cpp65 mcs/dbushelpers.cpp
64 mcs/networkdeviceskeleton.cpp66 mcs/networkdeviceskeleton.cpp
6567
68 mcs/video/videoformat.cpp
69 mcs/video/buffer.cpp
70 mcs/video/bufferqueue.cpp
71 mcs/video/utils.cpp
72 mcs/video/utils_from_android.cpp
73 mcs/video/baseencoder.cpp
74 mcs/video/h264analyzer.cpp
75 mcs/video/measurepoint.cpp
76 mcs/video/statistics.cpp
77
78 mcs/streaming/mpegtspacketizer.cpp
79 mcs/streaming/rtpsender.cpp
80
81 mcs/mir/mediasender.cpp
82 mcs/mir/sourcemediamanagernext.cpp
83 mcs/mir/streamconnector.cpp
84 mcs/mir/streamrenderer.cpp
85
86 mcs/android/h264encoder.cpp
87
88 mcs/systemcontroller.cpp
89
90 mcs/ubuntu/powerd.cpp
91 mcs/ubuntu/unity.cpp
92 mcs/ubuntu/systemcontroller.cpp
93 mcs/ubuntu/powerdsystemlock.cpp
94 mcs/ubuntu/unitydisplaylock.cpp
95
66 ${CMAKE_CURRENT_BINARY_DIR}/mcs/wpasupplicantinterface.c96 ${CMAKE_CURRENT_BINARY_DIR}/mcs/wpasupplicantinterface.c
67 w11tng/networkmanager.cpp97 w11tng/networkmanager.cpp
68 w11tng/networkdevice.cpp98 w11tng/networkdevice.cpp
@@ -83,20 +113,19 @@
83 w11tng/hostname1stub.cpp113 w11tng/hostname1stub.cpp
84)114)
85115
86link_directories(
87 ${GLIB_LIBRARY_DIRS}
88 ${GIO_LIBRARY_DIRS}
89 ${GIO-UNIX_LIBRARY_DIRS}
90 ${WDS_LIBRARY_DIRS}
91)
92
93include_directories(116include_directories(
94 ${Boost_INCLUDE_DIRS}117 ${Boost_INCLUDE_DIRS}
95 ${GLIB_INCLUDE_DIRS}118 ${GLIB_INCLUDE_DIRS}
96 ${GIO_INCLUDE_DIRS}119 ${GIO_INCLUDE_DIRS}
97 ${GIO-UNIX_INCLUDE_DIRS}120 ${GIO-UNIX_INCLUDE_DIRS}
98 ${GST_INCLUDE_DIRS}121 ${GST_INCLUDE_DIRS}
122 ${GST_APP_INCLUDE_DIRS}
99 ${WDS_INCLUDE_DIRS}123 ${WDS_INCLUDE_DIRS}
124 ${HYBRIS_MEDIA_INCLDUE_DIRS}
125 ${ANDROID_HEADERS_INCLUDE_DIRS}
126 ${MIRCLIENT_INCLUDE_DIRS}
127 ${EGL_INCLUDE_DIRS}
128 ${GLESV2_INCLUDE_DIRS}
100 ${CMAKE_CURRENT_BINARY_DIR}/src129 ${CMAKE_CURRENT_BINARY_DIR}/src
101 ${CMAKE_CURRENT_BINARY_DIR}/src/w11tng130 ${CMAKE_CURRENT_BINARY_DIR}/src/w11tng
102)131)
@@ -106,13 +135,29 @@
106add_executable(aethercast mcs/main.cpp)135add_executable(aethercast mcs/main.cpp)
107136
108target_link_libraries(aethercast-core137target_link_libraries(aethercast-core
138 ${Boost_LDFLAGS}
109 ${Boost_LIBRARIES}139 ${Boost_LIBRARIES}
140 ${GLIB_LDFLAGS}
110 ${GLIB_LIBRARIES}141 ${GLIB_LIBRARIES}
142 ${GIO_LDFLAGS}
111 ${GIO_LIBRARIES}143 ${GIO_LIBRARIES}
144 ${GIO-UNIX_LDFLAGS}
112 ${GIO-UNIX_LIBRARIES}145 ${GIO-UNIX_LIBRARIES}
146 ${GST_LDFLAGS}
113 ${GST_LIBRARIES}147 ${GST_LIBRARIES}
148 ${GST_APP_LDFLAGS}
149 ${GST_APP_LIBRARIES}
114 ${CMAKE_THREAD_LIBS_INIT}150 ${CMAKE_THREAD_LIBS_INIT}
151 ${WDS_LDFLAGS}
115 ${WDS_LIBRARIES}152 ${WDS_LIBRARIES}
153 ${HYBRIS_MEDIA_LDFLAGS}
154 ${HYBRIS_MEDIA_LIBRARIES}
155 ${MIRCLIENT_LDFLAGS}
156 ${MIRCLIENT_LIBRARIES}
157 ${EGL_LDFLAGS}
158 ${EGL_LIBRARIES}
159 ${GLESV2_LDFLAGS}
160 ${GLESV2_LIBRARIES}
116 -ldl161 -ldl
117)162)
118163
119164
=== added directory 'src/mcs/android'
=== added file 'src/mcs/android/h264encoder.cpp'
--- src/mcs/android/h264encoder.cpp 1970-01-01 00:00:00 +0000
+++ src/mcs/android/h264encoder.cpp 2016-02-25 12:47:02 +0000
@@ -0,0 +1,464 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <system/window.h>
19
20#include "mcs/logger.h"
21
22#include "mcs/video/statistics.h"
23
24#include "mcs/android/h264encoder.h"
25
26namespace {
27static const char *kEncoderThreadName{"H264Encoder"};
28static const char *kH264MimeType{"video/avc"};
29static const char *kRawMimeType{"video/raw"};
30// From frameworks/native/include/media/openmax/OMX_IVCommon.h
31const int32_t kOMXColorFormatAndroidOpaque = 0x7F000789;
32const int32_t kOMXVideoIntraRefreshCyclic = 0;
33// From frameworks/native/include/media/openmax/OMX_Video.h
34const int32_t kOMXVideoControlRateConstant = 2;
35// From frameworks/native/include/media/hardware/MetadataBufferType.h
36const uint32_t kMetadataBufferTypeGrallocSource = 1;
37// From frameworks/av/include/media/stagefright/MediaErrors.h
38enum AndroidMediaError {
39 kAndroidMediaErrorBase = -1000,
40 kAndroidMediaErrorEndOfStream = kAndroidMediaErrorBase - 11,
41};
42}
43
44namespace mcs {
45namespace android {
46
47class MediaSourceBuffer : public video::Buffer
48{
49public:
50 typedef std::shared_ptr<MediaSourceBuffer> Ptr;
51
52 ~MediaSourceBuffer() {
53 if (!buffer_)
54 return;
55
56 auto ref_count = media_buffer_get_refcount(buffer_);
57
58 // If someone has set a reference on the buffer we just have to
59 // release it here and the other one will take care about actually
60 // destroying it.
61 if (ref_count > 0)
62 media_buffer_release(buffer_);
63 else
64 media_buffer_destroy(buffer_);
65
66 }
67
68 static MediaSourceBuffer::Ptr Create(MediaBufferWrapper *buffer) {
69 auto sp = std::shared_ptr<MediaSourceBuffer>(new MediaSourceBuffer);
70 sp->buffer_ = buffer;
71 sp->ExtractTimestamp();
72 return sp;
73 }
74
75 virtual uint32_t Length() const {
76 if (!buffer_)
77 return 0;
78
79 return media_buffer_get_size(buffer_);
80 }
81
82 virtual uint8_t* Data() {
83 if (!buffer_)
84 return nullptr;
85
86 return static_cast<uint8_t*>(media_buffer_get_data(buffer_));
87 }
88
89 virtual bool IsValid() const {
90 return buffer_ != nullptr;
91 }
92
93private:
94 MediaSourceBuffer() { }
95
96 void ExtractTimestamp() {
97 auto meta_data = media_buffer_get_meta_data(buffer_);
98 if (!meta_data)
99 return;
100
101 uint32_t key_time = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_TIME);
102 int64_t time_us = 0;
103 media_meta_data_find_int64(meta_data, key_time, &time_us);
104
105 SetTimestamp(time_us);
106 }
107
108private:
109 MediaBufferWrapper *buffer_;
110};
111
112video::BaseEncoder::Config H264Encoder::DefaultConfiguration() {
113 Config config;
114 // Supplying -1 as framerate means the encoder decides on what it
115 // can provide.
116 config.framerate = -1;
117 config.bitrate = 5000000;
118 config.i_frame_interval = 15;
119 config.intra_refresh_mode = kOMXVideoIntraRefreshCyclic;
120 return config;
121}
122
123H264Encoder::Ptr H264Encoder::Create() {
124 return std::shared_ptr<H264Encoder>(new H264Encoder);
125}
126
127H264Encoder::H264Encoder() :
128 format_(nullptr),
129 encoder_(nullptr),
130 running_(false),
131 input_queue_(mcs::video::BufferQueue::Create()),
132 start_time_(-1ll),
133 frame_count_(0) {
134}
135
136H264Encoder::~H264Encoder() {
137 Stop();
138
139 if (encoder_)
140 media_codec_source_release(encoder_);
141
142 if (source_)
143 delete source_; /* media_source_release(source_); */
144
145 if (format_)
146 media_message_release(format_);
147}
148
149bool H264Encoder::IsValid() const {
150 return true;
151}
152
153bool H264Encoder::Configure(const Config &config) {
154 if (encoder_)
155 return false;
156
157 MCS_DEBUG("configuring with %dx%d@%d", config.width, config.height, config.framerate);
158
159 auto format = media_message_create();
160 if (!format)
161 return false;
162
163 media_message_set_string(format, "mime", kH264MimeType, 0);
164
165 media_message_set_int32(format, "store-metadata-in-buffers", true);
166 media_message_set_int32(format, "store-metadata-in-buffers-output", false);
167
168 media_message_set_int32(format, "width", config.width);
169 media_message_set_int32(format, "height", config.height);
170 media_message_set_int32(format, "stride", config.width);
171 media_message_set_int32(format, "slice-height", config.width);
172
173 media_message_set_int32(format, "color-format", kOMXColorFormatAndroidOpaque);
174
175 media_message_set_int32(format, "bitrate", config.bitrate);
176 media_message_set_int32(format, "bitrate-mode", kOMXVideoControlRateConstant);
177 media_message_set_int32(format, "frame-rate", config.framerate);
178
179 media_message_set_int32(format, "intra-refresh-mode", 0);
180
181 // Update macroblocks in a cyclic fashion with 10% of all MBs within
182 // frame gets updated at one time. It takes about 10 frames to
183 // completely update a whole video frame. If the frame rate is 30,
184 // it takes about 333 ms in the best case (if next frame is not an IDR)
185 // to recover from a lost/corrupted packet.
186 int32_t mbs = (((config.width + 15) / 16) * ((config.height + 15) / 16) * 10) / 100;
187 media_message_set_int32(format, "intra-refresh-CIR-mbs", mbs);
188
189 if (config.i_frame_interval > 0)
190 media_message_set_int32(format, "i-frame-interval", config.i_frame_interval);
191
192 if (config.profile_idc > 0)
193 media_message_set_int32(format, "profile-idc", config.profile_idc);
194
195 if (config.level_idc > 0)
196 media_message_set_int32(format, "level-idc", config.level_idc);
197
198 if (config.constraint_set > 0)
199 media_message_set_int32(format, "constraint-set", config.constraint_set);
200
201 // FIXME we need to find a way to check if the encoder supports prepending
202 // SPS/PPS to the buffers it is producing or if we have to manually do that
203 media_message_set_int32(format, "prepend-sps-pps-to-idr-frames", 1);
204
205 source_ = media_source_create();
206 if (!source_) {
207 MCS_ERROR("Failed to create media input source for encoder");
208 media_message_release(format);
209 return false;
210 }
211
212 auto source_format = media_meta_data_create();
213
214 // Notice that we're passing video/raw as mime type here which is quite
215 // important to let the encoder do the right thing with the incoming data
216 media_meta_data_set_cstring(source_format,
217 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_MIME),
218 kRawMimeType);
219
220 // We're setting the opaque color format here as the encoder is then
221 // meant to figure out the color format from the GL frames itself.
222 media_meta_data_set_int32(source_format,
223 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_COLOR_FORMAT),
224 kOMXColorFormatAndroidOpaque);
225
226 media_meta_data_set_int32(source_format,
227 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_WIDTH),
228 config.width);
229 media_meta_data_set_int32(source_format,
230 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_HEIGHT),
231 config.height);
232 media_meta_data_set_int32(source_format,
233 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_STRIDE),
234 config.width);
235 media_meta_data_set_int32(source_format,
236 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_SLICE_HEIGHT),
237 config.height);
238 media_meta_data_set_int32(source_format,
239 media_meta_data_get_key_id(MEDIA_META_DATA_KEY_FRAMERATE),
240 config.framerate);
241
242 media_source_set_format(source_, source_format);
243
244 media_source_set_start_callback(source_, &H264Encoder::OnSourceStart, this);
245 media_source_set_stop_callback(source_, &H264Encoder::OnSourceStop, this);
246 media_source_set_read_callback(source_, &H264Encoder::OnSourceRead, this);
247 media_source_set_pause_callback(source_, &H264Encoder::OnSourcePause, this);
248
249 encoder_ = media_codec_source_create(format, source_, 0);
250 if (!encoder_) {
251 MCS_ERROR("Failed to create encoder instance");
252 return false;
253 }
254
255 config_ = config;
256 format_ = format;
257
258 MCS_DEBUG("Configured encoder succesfully");
259
260 return true;
261}
262
263void H264Encoder::Start() {
264 if (!encoder_ || running_)
265 return;
266
267 if (!media_codec_source_start(encoder_)) {
268 MCS_ERROR("Failed to start encoder");
269 return;
270 }
271
272 worker_thread_ = std::thread(&H264Encoder::WorkerThread, this);
273 pthread_setname_np(worker_thread_.native_handle(), kEncoderThreadName);
274
275 running_ = true;
276
277 MCS_DEBUG("Started encoder");
278}
279
280int H264Encoder::OnSourceStart(MediaMetaDataWrapper *meta, void *user_data) {
281 auto thiz = static_cast<H264Encoder*>(user_data);
282
283 MCS_DEBUG("");
284
285 return 0;
286}
287
288int H264Encoder::OnSourceStop(void *user_data) {
289 auto thiz = static_cast<H264Encoder*>(user_data);
290
291 MCS_DEBUG("");
292
293 return 0;
294}
295
296MediaBufferWrapper* H264Encoder::PackBuffer(const mcs::video::Buffer::Ptr &input_buffer, const mcs::TimestampUs &timestamp) {
297 if (!input_buffer->NativeHandle()) {
298 MCS_WARNING("Ignoring buffer without native handle");
299 return nullptr;
300 }
301
302 auto anwb = reinterpret_cast<ANativeWindowBuffer*>(input_buffer->NativeHandle());
303
304 size_t size = sizeof(buffer_handle_t) + 4;
305
306 // We let the media buffer allocate the memory here to let it keep
307 // the ownership and release the memory once its destroyed.
308 auto buffer = media_buffer_create(size);
309 auto data = media_buffer_get_data(buffer);
310
311 // We're passing the buffer handle directly as part of the buffer data
312 // here to the encoder and it will figure out it has to deal with a
313 // buffer with the key value we put in front of it. See also
314 // frameworks/av/media/libstagefright/SurfaceMediaSource.cpp for more
315 // details about this.
316 uint32_t type = kMetadataBufferTypeGrallocSource;
317 memcpy(data, &type, 4);
318 memcpy(data + 4, &anwb->handle, sizeof(buffer_handle_t));
319
320 media_buffer_set_return_callback(buffer, &H264Encoder::OnBufferReturned, this);
321
322 // We need to put a reference on the buffer here if we want the
323 // callback we set above being called.
324 media_buffer_ref(buffer);
325
326 auto meta = media_buffer_get_meta_data(buffer);
327 auto key_time = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_TIME);
328 media_meta_data_set_int64(meta, key_time, timestamp);
329
330 pending_buffers_.push_back(BufferItem{input_buffer, buffer});
331
332 return buffer;
333}
334
335int H264Encoder::OnSourceRead(MediaBufferWrapper **buffer, void *user_data) {
336 auto thiz = static_cast<H264Encoder*>(user_data);
337
338 auto input_buffer = thiz->input_queue_->Next();
339
340
341 auto next_buffer = thiz->PackBuffer(input_buffer, input_buffer->Timestamp());
342
343 if (!next_buffer)
344 return kAndroidMediaErrorEndOfStream;
345
346 *buffer = next_buffer;
347
348 return 0;
349}
350
351int H264Encoder::OnSourcePause(void *user_data) {
352 auto thiz = static_cast<H264Encoder*>(user_data);
353
354 MCS_DEBUG("");
355
356 return 0;
357}
358
359void H264Encoder::OnBufferReturned(MediaBufferWrapper *buffer, void *user_data) {
360 auto thiz = static_cast<H264Encoder*>(user_data);
361
362 // Find the right pending buffer matching the returned one
363 auto iter = thiz->pending_buffers_.begin();
364 for (; iter != thiz->pending_buffers_.end(); ++iter) {
365 if (iter->media_buffer == buffer)
366 break;
367 }
368
369 if (iter == thiz->pending_buffers_.end()) {
370 MCS_WARNING("Didn't remember returned buffer!?");
371 return;
372 }
373
374 // Unset observer to be able to call release on the MediaBuffer
375 // and reduce its reference count. It has an internal check if
376 // an observer is still set or not before it will actually release
377 // itself.
378 media_buffer_set_return_callback(iter->media_buffer, nullptr, nullptr);
379 media_buffer_release(iter->media_buffer);
380
381 auto buf = iter->buffer;
382 thiz->pending_buffers_.erase(iter);
383
384 // After we've cleaned up everything we can send the buffer
385 // back to the producer which then can reuse it.
386 buf->Release();
387}
388
389bool H264Encoder::DoesBufferContainCodecConfig(MediaBufferWrapper *buffer) {
390 auto meta_data = media_buffer_get_meta_data(buffer);
391 if (!meta_data)
392 return false;
393
394 uint32_t key_is_codec_config = media_meta_data_get_key_id(MEDIA_META_DATA_KEY_IS_CODEC_CONFIG);
395 int32_t is_codec_config = 0;
396 media_meta_data_find_int32(meta_data, key_is_codec_config, &is_codec_config);
397 return static_cast<bool>(is_codec_config);
398}
399
400void H264Encoder::WorkerThread() {
401 MCS_DEBUG("Encoder worker thread is running");
402
403 while (running_) {
404 MediaBufferWrapper *buffer = nullptr;
405 if (!media_codec_source_read(encoder_, &buffer)) {
406 MCS_ERROR("Failed to read a new buffer from encoder");
407 return;
408 }
409
410 auto mbuf = MediaSourceBuffer::Create(buffer);
411
412 if (mbuf->Timestamp() > 0) {
413 int64_t now = mcs::Utils::GetNowUs();
414 int64_t diff = (now - mbuf->Timestamp()) / 1000ll;
415 video::Statistics::Instance()->RecordEncoderBufferOut(diff);
416 }
417
418 if (DoesBufferContainCodecConfig(buffer)) {
419 if (auto sp = delegate_.lock())
420 sp->OnBufferWithCodecConfig(mbuf);
421 }
422
423 if (auto sp = delegate_.lock())
424 sp->OnBufferAvailable(mbuf);
425 }
426}
427
428void H264Encoder::Stop() {
429 if (!encoder_ || !running_)
430 return;
431
432 if (!media_codec_source_stop(encoder_))
433 return;
434
435 running_ = false;
436 worker_thread_.join();
437}
438
439void H264Encoder::QueueBuffer(const video::Buffer::Ptr &buffer) {
440 input_queue_->Push(buffer);
441}
442
443void* H264Encoder::NativeWindowHandle() const {
444 if (!encoder_)
445 return nullptr;
446
447 return media_codec_source_get_native_window_handle(encoder_);
448}
449
450video::BaseEncoder::Config H264Encoder::Configuration() const {
451 return config_;
452}
453
454void H264Encoder::SendIDRFrame() {
455 if (!encoder_)
456 return;
457
458 MCS_DEBUG("");
459
460 media_codec_source_request_idr_frame(encoder_);
461}
462
463} // namespace android
464} // namespace mcs
0465
=== added file 'src/mcs/android/h264encoder.h'
--- src/mcs/android/h264encoder.h 1970-01-01 00:00:00 +0000
+++ src/mcs/android/h264encoder.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,96 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MCS_ANDORID_ENCODER_H_
19#define MCS_ANDORID_ENCODER_H_
20
21#include <memory>
22#include <thread>
23
24#include <hybris/media/media_codec_source_layer.h>
25
26#include "mcs/non_copyable.h"
27#include "mcs/utils.h"
28
29#include "mcs/video/baseencoder.h"
30#include "mcs/video/bufferqueue.h"
31
32namespace mcs {
33namespace android {
34class H264Encoder : public video::BaseEncoder {
35public:
36 typedef std::shared_ptr<H264Encoder> Ptr;
37
38 static BaseEncoder::Config DefaultConfiguration();
39
40 static Ptr Create();
41
42 ~H264Encoder();
43
44 bool IsValid() const override;
45
46 bool Configure(const BaseEncoder::Config &config);
47
48 void Start() override;
49 void Stop() override;
50
51 void QueueBuffer(const mcs::video::Buffer::Ptr &buffer);
52
53 void* NativeWindowHandle() const override;
54 BaseEncoder::Config Configuration() const override;
55
56 void SendIDRFrame() override;
57
58private:
59 H264Encoder();
60
61 void WorkerThread();
62
63 bool DoesBufferContainCodecConfig(MediaBufferWrapper *buffer);
64
65 MediaBufferWrapper* PackBuffer(const mcs::video::Buffer::Ptr &input_buffer, const mcs::TimestampUs &timestamp);
66
67private:
68 static int OnSourceStart(MediaMetaDataWrapper *meta, void *user_data);
69 static int OnSourceStop(void *user_data);
70 static int OnSourceRead(MediaBufferWrapper **buffer, void *user_data);
71 static int OnSourcePause(void *user_data);
72
73 static void OnBufferReturned(MediaBufferWrapper *buffer, void *user_data);
74
75private:
76 struct BufferItem {
77 mcs::video::Buffer::Ptr buffer;
78 MediaBufferWrapper *media_buffer;
79 };
80
81private:
82 BaseEncoder::Config config_;
83 MediaMessageWrapper *format_;
84 MediaSourceWrapper *source_;
85 MediaCodecSourceWrapper *encoder_;
86 bool running_;
87 std::thread worker_thread_;
88 mcs::video::BufferQueue::Ptr input_queue_;
89 std::vector<BufferItem> pending_buffers_;
90 mcs::TimestampUs start_time_;
91 uint32_t frame_count_;
92};
93} // namespace android
94} // namespace mcs
95
96#endif
097
=== modified file 'src/mcs/basesourcemediamanager.cpp'
--- src/mcs/basesourcemediamanager.cpp 2015-12-07 16:02:43 +0000
+++ src/mcs/basesourcemediamanager.cpp 2016-02-25 12:47:02 +0000
@@ -15,12 +15,23 @@
15 *15 *
16 */16 */
1717
18#include <iostream>
19
18#include <glib.h>20#include <glib.h>
1921
20#include "basesourcemediamanager.h"22#include "mcs/logger.h"
21#include "logger.h"23#include "mcs/basesourcemediamanager.h"
24#include "mcs/video/videoformat.h"
25
26namespace {
27static unsigned int next_session_id = 0;
28}
2229
23namespace mcs {30namespace mcs {
31BaseSourceMediaManager::BaseSourceMediaManager() :
32 session_id_(++next_session_id) {
33}
34
24wds::SessionType BaseSourceMediaManager::GetSessionType() const {35wds::SessionType BaseSourceMediaManager::GetSessionType() const {
25 return wds::VideoSession;36 return wds::VideoSession;
26}37}
@@ -38,24 +49,29 @@
38 return sink_port1_;49 return sink_port1_;
39}50}
4051
41std::vector<wds::H264VideoCodec> GetH264VideoCodecs() {52std::vector<wds::H264VideoCodec> BaseSourceMediaManager::GetH264VideoCodecs() {
42 static std::vector<wds::H264VideoCodec> codecs;53 static std::vector<wds::H264VideoCodec> codecs;
43 if (codecs.empty()) {54 if (codecs.empty()) {
44 wds::RateAndResolutionsBitmap cea_rr;55 wds::RateAndResolutionsBitmap cea_rr;
45 wds::RateAndResolutionsBitmap vesa_rr;56 wds::RateAndResolutionsBitmap vesa_rr;
46 wds::RateAndResolutionsBitmap hh_rr;57 wds::RateAndResolutionsBitmap hh_rr;
47 wds::RateAndResolution i;58
48 // declare that we support all resolutions, CHP and level 4.259 // We only support 720p here for now as that is our best performing
49 // gstreamer should handle all of it :)60 // resolution with regard of all other bits in the pipeline. Eventually
50 for (i = wds::CEA640x480p60; i <= wds::CEA1920x1080p24; ++i)61 // we will add 60 Hz here too but for now only everything up to 30 Hz.
51 cea_rr.set(i);62 cea_rr.set(wds::CEA1280x720p30);
52 for (i = wds::VESA800x600p30; i <= wds::VESA1920x1200p30; ++i)63 cea_rr.set(wds::CEA1280x720p25);
53 vesa_rr.set(i);64 cea_rr.set(wds::CEA1280x720p24);
54 for (i = wds::HH800x480p30; i <= wds::HH848x480p60; ++i)65
55 hh_rr.set(i);66 // FIXME which profiles and formats we support highly depends on what
5667 // android supports. But for now we just consider CBP with level 3.1
57 wds::H264VideoCodec codec(wds::CHP, wds::k4_2, cea_rr, vesa_rr, hh_rr);68 // as that is the same Android configures its setup with.
58 codecs.push_back(codec);69 wds::H264VideoCodec codec1(wds::CBP, wds::k3_1, cea_rr, vesa_rr, hh_rr);
70 codecs.push_back(codec1);
71
72 DEBUG("Video codecs supported by us:");
73 for (auto c : codecs)
74 mcs::video::DumpVideoCodec(c);
59 }75 }
6076
61 return codecs;77 return codecs;
@@ -64,19 +80,32 @@
64bool BaseSourceMediaManager::InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,80bool BaseSourceMediaManager::InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,
65 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) {81 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) {
6682
83 DEBUG("Sink native resolution:");
84 mcs::video::DumpNativeFormat(sink_native_format);
85
86 DEBUG("Sink supports the following codecs:");
87 for (auto sink_codec : sink_supported_codecs) {
88 mcs::video::DumpVideoCodec(sink_codec);
89 }
90
91 bool success = false;
92
67 format_ = wds::FindOptimalVideoFormat(sink_native_format,93 format_ = wds::FindOptimalVideoFormat(sink_native_format,
68 GetH264VideoCodecs(),94 GetH264VideoCodecs(),
69 sink_supported_codecs);95 sink_supported_codecs,
7096 &success);
71 INFO("Found optimal video format");97
72 INFO(" profile: %d", format_.profile);98 // Workaround buggy wds code ..
73 INFO(" level: %d", format_.level);99 if (format_.rate_resolution == wds::CEA1280x720p60)
74 INFO(" res type %d", format_.type);100 format_.rate_resolution = wds::CEA1280x720p30;
75 INFO(" rate & resolution %d", format_.rate_resolution);101
76102 if (!success)
77 Configure();103 MCS_WARNING("Failed to select proper video format");
78104
79 return true;105 DEBUG("Found optimal video format:");
106 mcs::video::DumpVideoFormat(format_);
107
108 return Configure();
80}109}
81110
82wds::H264VideoFormat BaseSourceMediaManager::GetOptimalVideoFormat() const {111wds::H264VideoFormat BaseSourceMediaManager::GetOptimalVideoFormat() const {
@@ -102,4 +131,8 @@
102void BaseSourceMediaManager::SendIDRPicture() {131void BaseSourceMediaManager::SendIDRPicture() {
103 WARNING("Unimplemented IDR picture request");132 WARNING("Unimplemented IDR picture request");
104}133}
134
135std::string BaseSourceMediaManager::GetSessionId() const {
136 return mcs::Utils::Sprintf("%d", session_id_);
137}
105} // namespace mcs138} // namespace mcs
106139
=== modified file 'src/mcs/basesourcemediamanager.h'
--- src/mcs/basesourcemediamanager.h 2015-11-26 16:48:53 +0000
+++ src/mcs/basesourcemediamanager.h 2016-02-25 12:47:02 +0000
@@ -24,9 +24,11 @@
24class BaseSourceMediaManager : public wds::SourceMediaManager24class BaseSourceMediaManager : public wds::SourceMediaManager
25{25{
26public:26public:
27 explicit BaseSourceMediaManager();
28
27 void SetSinkRtpPorts(int port1, int port2) override;29 void SetSinkRtpPorts(int port1, int port2) override;
28 std::pair<int,int> GetSinkRtpPorts() const override;30 std::pair<int,int> GetSinkRtpPorts() const override;
29 int GetLocalRtpPort() const override;31 virtual int GetLocalRtpPort() const override;
30 wds::SessionType GetSessionType() const override;32 wds::SessionType GetSessionType() const override;
3133
32 bool InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,34 bool InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,
@@ -34,15 +36,18 @@
34 wds::H264VideoFormat GetOptimalVideoFormat() const override;36 wds::H264VideoFormat GetOptimalVideoFormat() const override;
35 bool InitOptimalAudioFormat(const std::vector<wds::AudioCodec>& sink_supported_codecs) override;37 bool InitOptimalAudioFormat(const std::vector<wds::AudioCodec>& sink_supported_codecs) override;
36 wds::AudioCodec GetOptimalAudioFormat() const override;38 wds::AudioCodec GetOptimalAudioFormat() const override;
37 void SendIDRPicture() override;39 virtual void SendIDRPicture() override;
40 std::string GetSessionId() const override;
3841
39protected:42protected:
40 virtual void Configure() = 0;43 virtual bool Configure() = 0;
44 virtual std::vector<wds::H264VideoCodec> GetH264VideoCodecs();
4145
42protected:46protected:
43 int sink_port1_;47 int sink_port1_;
44 int sink_port2_;48 int sink_port2_;
45 wds::H264VideoFormat format_;49 wds::H264VideoFormat format_;
50 unsigned int session_id_;
46};51};
47} // namespace mcs52} // namespace mcs
48#endif53#endif
4954
=== added file 'src/mcs/config.h.in'
--- src/mcs/config.h.in 1970-01-01 00:00:00 +0000
+++ src/mcs/config.h.in 2016-02-25 12:47:02 +0000
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MCS_CONFIG_H_
19#define MCS_CONFIG_H_
20
21namespace mcs {
22constexpr const char* kRuntimePath{"/run/aethercast"};
23}
24
25#endif
026
=== removed file 'src/mcs/config.h.in'
--- src/mcs/config.h.in 2016-01-19 21:50:49 +0000
+++ src/mcs/config.h.in 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MCS_CONFIG_H_
19#define MCS_CONFIG_H_
20
21namespace mcs {
22constexpr const char* kRuntimePath{"/run/aethercast"};
23}
24
25#endif
260
=== modified file 'src/mcs/forwardingmiracastcontroller.cpp'
--- src/mcs/forwardingmiracastcontroller.cpp 2016-01-21 13:25:31 +0000
+++ src/mcs/forwardingmiracastcontroller.cpp 2016-02-25 12:47:02 +0000
@@ -42,8 +42,12 @@
42 fwd_->Disconnect(device, callback);42 fwd_->Disconnect(device, callback);
43}43}
4444
45void ForwardingMiracastController::Scan(const std::chrono::seconds &timeout) {45void ForwardingMiracastController::DisconnectAll(ResultCallback callback) {
46 fwd_->Scan(timeout);46 fwd_->DisconnectAll(callback);
47}
48
49mcs::Error ForwardingMiracastController::Scan(const std::chrono::seconds &timeout) {
50 return fwd_->Scan(timeout);
47}51}
4852
49NetworkDeviceState ForwardingMiracastController::State() const {53NetworkDeviceState ForwardingMiracastController::State() const {
5054
=== modified file 'src/mcs/forwardingmiracastcontroller.h'
--- src/mcs/forwardingmiracastcontroller.h 2016-01-21 13:25:31 +0000
+++ src/mcs/forwardingmiracastcontroller.h 2016-02-25 12:47:02 +0000
@@ -32,7 +32,9 @@
32 virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) override;32 virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) override;
33 virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) override;33 virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) override;
3434
35 virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;35 virtual void DisconnectAll(ResultCallback callback) override;
36
37 virtual mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;
3638
37 virtual NetworkDeviceState State() const override;39 virtual NetworkDeviceState State() const override;
38 virtual std::vector<NetworkManager::Capability> Capabilities() const override;40 virtual std::vector<NetworkManager::Capability> Capabilities() const override;
3941
=== removed file 'src/mcs/forwardingnetworkdevice.cpp'
--- src/mcs/forwardingnetworkdevice.cpp 2015-12-16 08:04:35 +0000
+++ src/mcs/forwardingnetworkdevice.cpp 1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
1/*
2* Copyright (C) 2015 Canonical, Ltd.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU General Public License version 3, as published
6* by the Free Software Foundation.
7*
8* This program is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranties of
10* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11* PURPOSE. See the GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License along
14* with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16*/
17
18#include "forwardingnetworkdevice.h"
19
20namespace mcs {
21
22ForwardingNetworkDevice::ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd) : fwd_(fwd) {
23 if (not fwd_) {
24 throw std::logic_error{"Cannot operate without a valid NetworkDevice instance."};
25 }
26}
27
28MacAddress ForwardingNetworkDevice::Address() const {
29 return fwd_->Address();
30}
31
32IpV4Address ForwardingNetworkDevice::IPv4Address() const {
33 return fwd_->IPv4Address();
34}
35
36std::string ForwardingNetworkDevice::Name() const {
37 return fwd_->Name();
38}
39
40NetworkDeviceState ForwardingNetworkDevice::State() const {
41 return fwd_->State();
42}
43
44std::vector<NetworkDeviceRole> ForwardingNetworkDevice::SupportedRoles() const {
45 return fwd_->SupportedRoles();
46}
47
48const NetworkDevice::Ptr& ForwardingNetworkDevice::Fwd() const {
49 return fwd_;
50}
51} // namespace mcs
520
=== added file 'src/mcs/forwardingnetworkdevice.h'
--- src/mcs/forwardingnetworkdevice.h 1970-01-01 00:00:00 +0000
+++ src/mcs/forwardingnetworkdevice.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,42 @@
1/*
2* Copyright (C) 2015 Canonical, Ltd.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU General Public License version 3, as published
6* by the Free Software Foundation.
7*
8* This program is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranties of
10* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11* PURPOSE. See the GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License along
14* with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16*/
17
18#ifndef FORWARDINGNETWORKDEVICE_H_
19#define FORWARDINGNETWORKDEVICE_H_
20
21#include "networkdevice.h"
22
23namespace mcs {
24
25class ForwardingNetworkDevice : public NetworkDevice {
26public:
27 ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd);
28
29 MacAddress Address() const override;
30 IpV4Address IPv4Address() const override;
31 std::string Name() const override;
32 NetworkDeviceState State() const override;
33 std::vector<NetworkDeviceRole> SupportedRoles() const override;
34
35protected:
36 const NetworkDevice::Ptr& Fwd() const;
37
38private:
39 NetworkDevice::Ptr fwd_;
40};
41} // namespace mcs
42#endif
043
=== removed file 'src/mcs/forwardingnetworkdevice.h'
--- src/mcs/forwardingnetworkdevice.h 2015-12-16 08:04:35 +0000
+++ src/mcs/forwardingnetworkdevice.h 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
1/*
2* Copyright (C) 2015 Canonical, Ltd.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU General Public License version 3, as published
6* by the Free Software Foundation.
7*
8* This program is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranties of
10* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11* PURPOSE. See the GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License along
14* with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16*/
17
18#ifndef FORWARDINGNETWORKDEVICE_H_
19#define FORWARDINGNETWORKDEVICE_H_
20
21#include "networkdevice.h"
22
23namespace mcs {
24
25class ForwardingNetworkDevice : public NetworkDevice {
26public:
27 ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd);
28
29 MacAddress Address() const override;
30 IpV4Address IPv4Address() const override;
31 std::string Name() const override;
32 NetworkDeviceState State() const override;
33 std::vector<NetworkDeviceRole> SupportedRoles() const override;
34
35protected:
36 const NetworkDevice::Ptr& Fwd() const;
37
38private:
39 NetworkDevice::Ptr fwd_;
40};
41} // namespace mcs
42#endif
430
=== modified file 'src/mcs/gstsourcemediamanager.cpp'
--- src/mcs/gstsourcemediamanager.cpp 2015-12-09 16:07:13 +0000
+++ src/mcs/gstsourcemediamanager.cpp 2016-02-25 12:47:02 +0000
@@ -60,48 +60,65 @@
60 g_free (debug);60 g_free (debug);
61 break;61 break;
62 default:62 default:
63 /* unhandled message */63 DEBUG("");
64 break;64 break;
65 }65 }
6666
67 return TRUE;67 return TRUE;
68}68}
6969
70void GstSourceMediaManager::Configure() {70bool GstSourceMediaManager::Configure() {
71 DEBUG("");
72
71 pipeline_ = ConstructPipeline(format_);73 pipeline_ = ConstructPipeline(format_);
74 if (!pipeline_)
75 return false;
7276
73 ScopedGObject<GstBus> bus{gst_pipeline_get_bus (GST_PIPELINE(pipeline_.get()))};77 ScopedGObject<GstBus> bus{gst_pipeline_get_bus (GST_PIPELINE(pipeline_.get()))};
74 bus_watch_id_ = gst_bus_add_watch(bus.get(), &GstSourceMediaManager::OnGstBusEvent, nullptr);78 bus_watch_id_ = gst_bus_add_watch(bus.get(), &GstSourceMediaManager::OnGstBusEvent, nullptr);
7579
76 // Prepare pipeline so we're ready to go as soon as needed80 // Prepare pipeline so we're ready to go as soon as needed
77 gst_element_set_state(pipeline_.get(), GST_STATE_READY);81 gst_element_set_state(pipeline_.get(), GST_STATE_READY);
82
83 return true;
78}84}
7985
80void GstSourceMediaManager::Play() {86void GstSourceMediaManager::Play() {
81 if (!pipeline_)87 if (!pipeline_)
82 return;88 return;
8389
90 DEBUG("");
91
84 gst_element_set_state(pipeline_.get(), GST_STATE_PLAYING);92 gst_element_set_state(pipeline_.get(), GST_STATE_PLAYING);
93 gst_element_get_state(pipeline_.get(), nullptr, nullptr, GST_CLOCK_TIME_NONE);
85}94}
8695
87void GstSourceMediaManager::Pause() {96void GstSourceMediaManager::Pause() {
88 if (!pipeline_)97 if (!pipeline_)
89 return;98 return;
9099
100 DEBUG("");
101
91 gst_element_set_state(pipeline_.get(), GST_STATE_PAUSED);102 gst_element_set_state(pipeline_.get(), GST_STATE_PAUSED);
103 gst_element_get_state(pipeline_.get(), nullptr, nullptr, GST_CLOCK_TIME_NONE);
92}104}
93105
94void GstSourceMediaManager::Teardown() {106void GstSourceMediaManager::Teardown() {
95 if (!pipeline_)107 if (!pipeline_)
96 return;108 return;
97109
110 DEBUG("");
111
98 gst_element_set_state(pipeline_.get(), GST_STATE_READY);112 gst_element_set_state(pipeline_.get(), GST_STATE_READY);
113 gst_element_get_state(pipeline_.get(), nullptr, nullptr, GST_CLOCK_TIME_NONE);
99}114}
100115
101bool GstSourceMediaManager::IsPaused() const {116bool GstSourceMediaManager::IsPaused() const {
102 if (!pipeline_)117 if (!pipeline_)
103 return true;118 return true;
104119
120 DEBUG("");
121
105 GstState state;122 GstState state;
106 gst_element_get_state(pipeline_.get(), &state, nullptr, GST_CLOCK_TIME_NONE);123 gst_element_get_state(pipeline_.get(), &state, nullptr, GST_CLOCK_TIME_NONE);
107124
108125
=== modified file 'src/mcs/gstsourcemediamanager.h'
--- src/mcs/gstsourcemediamanager.h 2015-11-30 16:16:49 +0000
+++ src/mcs/gstsourcemediamanager.h 2016-02-25 12:47:02 +0000
@@ -29,7 +29,7 @@
29 public BaseSourceMediaManager29 public BaseSourceMediaManager
30{30{
31public:31public:
32 ~GstSourceMediaManager();32 virtual ~GstSourceMediaManager();
3333
34 void Play() override;34 void Play() override;
35 void Pause() override;35 void Pause() override;
@@ -38,7 +38,7 @@
3838
39protected:39protected:
40 GstSourceMediaManager();40 GstSourceMediaManager();
41 void Configure() override;41 bool Configure() override;
4242
43 virtual SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) = 0;43 virtual SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) = 0;
4444
4545
=== added file 'src/mcs/initgstreameronce.cpp'
--- src/mcs/initgstreameronce.cpp 1970-01-01 00:00:00 +0000
+++ src/mcs/initgstreameronce.cpp 2016-02-25 12:47:02 +0000
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <atomic>
19
20#include <gst/gst.h>
21
22#include "initgstreameronce.h"
23#include "logger.h"
24
25namespace {
26void GstLog (GstDebugCategory *category,
27 GstDebugLevel level,
28 const gchar *file,
29 const gchar *function,
30 gint line,
31 GObject *object,
32 GstDebugMessage *message,
33 gpointer user_data) {
34
35 boost::optional<mcs::Logger::Location> location;
36 if (file && function && line > 0) {
37 location = mcs::Logger::Location{file, function, line};
38 }
39
40 mcs::Log().Log(mcs::GstDebugLevelToSeverity(level), gst_debug_message_get(message), location);
41}
42}
43namespace mcs {
44Logger::Severity GstDebugLevelToSeverity(GstDebugLevel level) {
45 switch (level) {
46 case GST_LEVEL_NONE:
47 case GST_LEVEL_ERROR:
48 return Logger::Severity::kError;
49 case GST_LEVEL_WARNING:
50 case GST_LEVEL_FIXME:
51 return Logger::Severity::kWarning;
52 case GST_LEVEL_INFO:
53 return Logger::Severity::kInfo;
54 case GST_LEVEL_DEBUG:
55 return Logger::Severity::kDebug;
56 case GST_LEVEL_LOG:
57 return Logger::Severity::kDebug;
58 case GST_LEVEL_TRACE:
59 case GST_LEVEL_MEMDUMP:
60 return Logger::Severity::kTrace;
61 default:
62 return Logger::Severity::kInfo;
63 }
64}
65
66void InitGstreamerOnceOrThrow() {
67 static std::atomic<bool> initialized(false);
68 if (initialized.exchange(true))
69 return;
70
71 GError* error = nullptr;
72 if (gst_init_check(nullptr, nullptr, &error) == FALSE) {
73 auto what = Utils::Sprintf("Failed to initialize gstreamer (%s: %s)", g_quark_to_string(error->domain), error->message);
74 g_error_free(error);
75 throw std::runtime_error{what};
76 }
77
78 // Get rid of gstreamer's default log function.
79 gst_debug_remove_log_function(nullptr);
80 // And install our own.
81 gst_debug_add_log_function(GstLog, nullptr, nullptr);
82 // No need to, our logging infra takes care of that, too.
83 gst_debug_set_colored(FALSE);
84 auto gst_debug = Utils::GetEnvValue("AETHERCAST_GST_DEBUG");
85 if (not gst_debug.empty())
86 gst_debug_set_threshold_from_string(gst_debug.c_str(), FALSE);
87}
88}
089
=== added file 'src/mcs/initgstreameronce.h'
--- src/mcs/initgstreameronce.h 1970-01-01 00:00:00 +0000
+++ src/mcs/initgstreameronce.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <gst/gst.h>
19
20#include "logger.h"
21
22namespace mcs {
23// GstDebugLevelToSeverity maps a GstDebugLevel to a Logger::Severity;
24Logger::Severity GstDebugLevelToSeverity(GstDebugLevel);
25
26// InitGstreamerOnceOrThrow initializes GStreamer, redirecting
27// its debug output to the mcs::Logger facilities.
28void InitGstreamerOnceOrThrow();
29}
030
=== modified file 'src/mcs/logger.cpp'
--- src/mcs/logger.cpp 2015-12-09 07:37:10 +0000
+++ src/mcs/logger.cpp 2016-02-25 12:47:02 +0000
@@ -15,6 +15,8 @@
15 *15 *
16 */16 */
1717
18#include <thread>
19
18#include "logger.h"20#include "logger.h"
1921
20#define BOOST_LOG_DYN_LINK22#define BOOST_LOG_DYN_LINK
@@ -34,7 +36,14 @@
34}36}
3537
36struct BoostLogLogger : public mcs::Logger {38struct BoostLogLogger : public mcs::Logger {
37 BoostLogLogger() {39 BoostLogLogger() :
40 initialized_(false) {
41 }
42
43 void Init(const mcs::Logger::Severity &severity = mcs::Logger::Severity::kWarning) override {
44 if (initialized_)
45 return;
46
38 boost::log::formatter formatter = boost::log::expressions::stream47 boost::log::formatter formatter = boost::log::expressions::stream
39 << "[" << attrs::Severity << " "48 << "[" << attrs::Severity << " "
40 << boost::log::expressions::format_date_time< boost::posix_time::ptime >("Timestamp", "%Y-%m-%d %H:%M:%S")49 << boost::log::expressions::format_date_time< boost::posix_time::ptime >("Timestamp", "%Y-%m-%d %H:%M:%S")
@@ -48,10 +57,16 @@
48 boost::log::core::get()->remove_all_sinks();57 boost::log::core::get()->remove_all_sinks();
49 auto logger = boost::log::add_console_log(std::cout);58 auto logger = boost::log::add_console_log(std::cout);
50 logger->set_formatter(formatter);59 logger->set_formatter(formatter);
51 // logger->set_filter(attrs::Severity < mcs::Logger::Severity::kInfo);60
61 // logger->set_filter(attrs::Severity < severity);
62
63 initialized_ = true;
52 }64 }
5365
54 void Log(Severity severity, const std::string& message, const boost::optional<Location> &loc) {66 void Log(Severity severity, const std::string& message, const boost::optional<Location> &loc) {
67 if (!initialized_)
68 Init();
69
55 if (auto rec = boost::log::trivial::logger::get().open_record()) {70 if (auto rec = boost::log::trivial::logger::get().open_record()) {
56 boost::log::record_ostream out{rec};71 boost::log::record_ostream out{rec};
57 out << boost::log::add_value(attrs::Severity, severity)72 out << boost::log::add_value(attrs::Severity, severity)
@@ -68,6 +83,9 @@
68 boost::log::trivial::logger::get().push_record(std::move(rec));83 boost::log::trivial::logger::get().push_record(std::move(rec));
69 }84 }
70 }85 }
86
87private:
88 bool initialized_;
71};89};
7290
73std::shared_ptr<mcs::Logger>& MutableInstance() {91std::shared_ptr<mcs::Logger>& MutableInstance() {
7492
=== modified file 'src/mcs/logger.h'
--- src/mcs/logger.h 2015-12-09 07:31:06 +0000
+++ src/mcs/logger.h 2016-02-25 12:47:02 +0000
@@ -48,6 +48,8 @@
48 std::uint32_t line; // The line in file that resulted in the log message.48 std::uint32_t line; // The line in file that resulted in the log message.
49 };49 };
5050
51 virtual void Init(const mcs::Logger::Severity &severity = mcs::Logger::Severity::kWarning) = 0;
52
51 virtual void Log(Severity severity, const std::string &message, const boost::optional<Location>& location) = 0;53 virtual void Log(Severity severity, const std::string &message, const boost::optional<Location>& location) = 0;
5254
53 virtual void Trace(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});55 virtual void Trace(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
@@ -57,6 +59,7 @@
57 virtual void Error(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});59 virtual void Error(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
58 virtual void Fatal(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});60 virtual void Fatal(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
5961
62
60 template<typename... T>63 template<typename... T>
61 void Tracef(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {64 void Tracef(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
62 Trace(Utils::Sprintf(pattern, std::forward<T>(args)...), location);65 Trace(Utils::Sprintf(pattern, std::forward<T>(args)...), location);
6366
=== modified file 'src/mcs/mediamanagerfactory.cpp'
--- src/mcs/mediamanagerfactory.cpp 2016-01-04 07:52:54 +0000
+++ src/mcs/mediamanagerfactory.cpp 2016-02-25 12:47:02 +0000
@@ -19,7 +19,7 @@
1919
20#include "logger.h"20#include "logger.h"
21#include "mediamanagerfactory.h"21#include "mediamanagerfactory.h"
22#include "mirsourcemediamanager.h"22#include "mir/sourcemediamanager.h"
23#include "x11sourcemediamanager.h"23#include "x11sourcemediamanager.h"
24#include "testsourcemediamanager.h"24#include "testsourcemediamanager.h"
25#include "utils.h"25#include "utils.h"
@@ -41,19 +41,23 @@
4141
42bool NullSourceMediaManager::IsPaused() const {42bool NullSourceMediaManager::IsPaused() const {
43 WARNING("NullSourceMediaManager: Not implemented");43 WARNING("NullSourceMediaManager: Not implemented");
44 return false;
44}45}
4546
46void NullSourceMediaManager::Configure() {47bool NullSourceMediaManager::Configure() {
47 WARNING("NullSourceMediaManager: Not implemented");48 WARNING("NullSourceMediaManager: Not implemented");
49 return false;
48}50}
4951
50std::shared_ptr<BaseSourceMediaManager> MediaManagerFactory::CreateSource(const std::string &remote_address) {52std::shared_ptr<BaseSourceMediaManager> MediaManagerFactory::CreateSource(const std::string &remote_address) {
51 std::string type = Utils::GetEnvValue("MIRACAST_SOURCE_TYPE");53 std::string type = Utils::GetEnvValue("MIRACAST_SOURCE_TYPE");
54 if (type.length() == 0)
55 type = "mir";
5256
53 DEBUG("Creating source media manager of type %s", type.c_str());57 DEBUG("Creating source media manager of type %s", type.c_str());
5458
55 if (type.length() == 0 || type == "mir")59 if (type == "mir")
56 return std::make_shared<MirSourceMediaManager>(remote_address);60 return mcs::mir::SourceMediaManager::Create(remote_address);
57 else if (type == "x11")61 else if (type == "x11")
58 return X11SourceMediaManager::create(remote_address);62 return X11SourceMediaManager::create(remote_address);
59 else if (type == "test")63 else if (type == "test")
6064
=== modified file 'src/mcs/mediamanagerfactory.h'
--- src/mcs/mediamanagerfactory.h 2015-12-02 15:13:13 +0000
+++ src/mcs/mediamanagerfactory.h 2016-02-25 12:47:02 +0000
@@ -33,7 +33,7 @@
33 bool IsPaused() const override;33 bool IsPaused() const override;
3434
35protected:35protected:
36 void Configure() override;36 bool Configure() override;
37};37};
3838
39class MediaManagerFactory {39class MediaManagerFactory {
4040
=== added directory 'src/mcs/mir'
=== added file 'src/mcs/mir/mediasender.cpp'
--- src/mcs/mir/mediasender.cpp 1970-01-01 00:00:00 +0000
+++ src/mcs/mir/mediasender.cpp 2016-02-25 12:47:02 +0000
@@ -0,0 +1,155 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <stdio.h>
19
20#include "mcs/logger.h"
21
22#include "mcs/video/statistics.h"
23
24#include "mcs/mir/mediasender.h"
25
26namespace {
27FILE *dump_file = nullptr;
28static constexpr const char *kMediaSenderThreadName{"MediaSender"};
29}
30
31namespace mcs {
32namespace mir {
33
34MediaSender::Ptr MediaSender::Create(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config) {
35 return std::shared_ptr<MediaSender>(new MediaSender(endpoint, config));
36}
37
38MediaSender::MediaSender(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config) :
39 prev_time_us_(-1ll),
40 queue_(video::BufferQueue::Create()),
41 running_(false) {
42
43 packetizer_ = streaming::MPEGTSPacketizer::Create();
44
45 // FIXME once we add support for audio this can be only used for video
46 // and we need to differentiate here per track.
47 streaming::MPEGTSPacketizer::TrackFormat format;
48 format.profile_idc = config.profile_idc;
49 format.level_idc = config.level_idc;
50 format.constraint_set = config.constraint_set;
51 format.mime = "video/avc";
52
53 video_track_ = packetizer_->AddTrack(format);
54
55 rtp_sender_ = streaming::RTPSender::Create();
56 rtp_sender_->Setup(endpoint.address, endpoint.port);
57
58 if (mcs::Utils::IsEnvSet("AETHERCAST_MPEGTS_DUMP"))
59 dump_file = ::fopen(mcs::Utils::GetEnvValue("AETHERCAST_MPEGTS_DUMP").c_str(), "w");
60}
61
62MediaSender::~MediaSender() {
63 if (dump_file)
64 ::fclose(dump_file);
65
66 Stop();
67}
68
69void MediaSender::Start() {
70 if (running_)
71 return;
72
73 running_ = true;
74 worker_thread_ = std::thread(&MediaSender::WorkerThread, this);
75 pthread_setname_np(worker_thread_.native_handle(), kMediaSenderThreadName);
76}
77
78void MediaSender::Stop() {
79 if (!running_)
80 return;
81
82 running_ = false;
83 worker_thread_.join();
84}
85
86void MediaSender::ProcessBuffer(const mcs::video::Buffer::Ptr &buffer) {
87 mcs::video::Buffer::Ptr packets;
88
89 static int64_t start_time_us = mcs::Utils::GetNowUs();
90 static unsigned int buffer_count = 0;
91
92 buffer_count++;
93 int64_t time_now_us = mcs::Utils::GetNowUs();
94 if (start_time_us + 1000000ll <= time_now_us) {
95 video::Statistics::Instance()->RecordSenderBufferPerSecond(buffer_count);
96 buffer_count = 0;
97 start_time_us = time_now_us;
98 }
99
100 // FIXME: By default we're expecting the encoder to insert SPS and PPS
101 // with each IDR frame but we need to handle also the case where the
102 // encoder is not capable of doing this.
103#if 0
104 int flags = streaming::MPEGTSPacketizer::kPrependSPSandPPStoIDRFrames;
105#else
106 int flags = 0;
107#endif
108
109 // Per spec we need to emit PAT/PMT and PCR updates atleast every 100ms
110 int64_t time_us = mcs::Utils::GetNowUs();
111 if (prev_time_us_ < 0ll || prev_time_us_ + 100000ll <= time_us) {
112 flags |= streaming::MPEGTSPacketizer::kEmitPATandPMT;
113 flags |= streaming::MPEGTSPacketizer::kEmitPCR;
114 prev_time_us_ = time_us;
115 }
116
117 if (!packetizer_->Packetize(video_track_, buffer, &packets, flags)) {
118 MCS_ERROR("MPEGTS packetizing failed");
119 return;
120 }
121
122 if (dump_file)
123 ::fwrite(packets->Data(), 1, packets->Length(), dump_file);
124
125 packets->SetTimestamp(buffer->Timestamp());
126 rtp_sender_->QueueTSPackets(packets);
127}
128
129void MediaSender::WorkerThread() {
130 while (running_) {
131 // This will wait for a short time and then return back
132 // so we can loop again and check if we have to exit or
133 // not.
134 if (!queue_->WaitToBeFilled())
135 continue;
136
137 auto buffer = queue_->Pop();
138 ProcessBuffer(buffer);
139 }
140}
141
142void MediaSender::OnBufferAvailable(const video::Buffer::Ptr &buffer) {
143 queue_->Push(buffer);
144}
145
146void MediaSender::OnBufferWithCodecConfig(const video::Buffer::Ptr &buffer) {
147 packetizer_->SubmitCSD(video_track_, buffer);
148}
149
150uint16_t MediaSender::LocalRTPPort() const {
151 return rtp_sender_->LocalPort();
152}
153
154} // namespace mir
155} // namespace mcs
0156
=== added file 'src/mcs/mir/mediasender.h'
--- src/mcs/mir/mediasender.h 1970-01-01 00:00:00 +0000
+++ src/mcs/mir/mediasender.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MCS_MIR_MEDIASENDER_H_
19#define MCS_MIR_MEDIASENDER_H_
20
21#include <memory>
22#include <mutex>
23
24#include "mcs/video/baseencoder.h"
25#include "mcs/video/bufferqueue.h"
26
27#include "mcs/streaming/mpegtspacketizer.h"
28#include "mcs/streaming/rtpsender.h"
29
30namespace mcs {
31namespace mir {
32
33class MediaSender : public std::enable_shared_from_this<MediaSender>,
34 public mcs::video::BaseEncoder::Delegate {
35public:
36 typedef std::shared_ptr<MediaSender> Ptr;
37
38 struct Endpoint {
39 std::string address;
40 unsigned int port;
41 };
42
43 static Ptr Create(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config);
44
45 ~MediaSender();
46
47 void Start();
48 void Stop();
49
50 void OnBufferAvailable(const mcs::video::Buffer::Ptr &buffer) override;
51 void OnBufferWithCodecConfig(const mcs::video::Buffer::Ptr &buffer) override;
52
53 uint16_t LocalRTPPort() const;
54
55private:
56 MediaSender(const Endpoint &endpoint, const mcs::video::BaseEncoder::Config &config);
57
58 void WorkerThread();
59
60 void ProcessBuffer(const mcs::video::Buffer::Ptr &buffer);
61
62private:
63 streaming::MPEGTSPacketizer::Ptr packetizer_;
64 streaming::RTPSender::Ptr rtp_sender_;
65 streaming::MPEGTSPacketizer::TrackId video_track_;
66 int64_t prev_time_us_;
67 std::thread worker_thread_;
68 mcs::video::BufferQueue::Ptr queue_;
69 bool running_;
70};
71
72} // namespace mir
73} // namespace mcs
74
75#endif
076
=== renamed file 'src/mcs/mirsourcemediamanager.cpp' => 'src/mcs/mir/sourcemediamanager.cpp'
--- src/mcs/mirsourcemediamanager.cpp 2015-12-07 16:02:43 +0000
+++ src/mcs/mir/sourcemediamanager.cpp 2016-02-25 12:47:02 +0000
@@ -15,99 +15,136 @@
15 *15 *
16 */16 */
1717
18#include <sstream>18#include "mcs/logger.h"
1919
20#include "mirsourcemediamanager.h"20#include "mcs/video/statistics.h"
21#include "utils.h"21#include "mcs/video/videoformat.h"
22#include "logger.h"22
23#include "mcs/mir/sourcemediamanager.h"
24
25#include "mcs/android/h264encoder.h"
2326
24namespace mcs {27namespace mcs {
25MirSourceMediaManager::MirSourceMediaManager(const std::string &remote_address) :28namespace mir {
26 remote_address_(remote_address) {29
27}30SourceMediaManager::Ptr SourceMediaManager::Create(const std::string &remote_address) {
2831 return std::shared_ptr<SourceMediaManager>(new SourceMediaManager(remote_address));
29MirSourceMediaManager::~MirSourceMediaManager() {32}
30}33
3134SourceMediaManager::SourceMediaManager(const std::string &remote_address) :
32SharedGObject<GstElement> MirSourceMediaManager::ConstructPipeline(const wds::H264VideoFormat &format) {35 remote_address_(remote_address),
33 int width = 0, height = 0;36 state_(State::Stopped) {
34 std::string profile = "constrained-baseline";37}
3538
36 switch (format.profile) {39SourceMediaManager::~SourceMediaManager() {
37 case wds::CBP:40 if (state_ != State::Stopped)
38 profile = "constrained-baseline";41 StopPipeline();
39 break;42
40 case wds::CHP:43 mcs::video::Statistics::Instance()->Dump();
41 profile = "high";44}
42 break;45
43 }46bool SourceMediaManager::Configure() {
4447 auto rr = mcs::video::ExtractRateAndResolution(format_);
45 switch (format.type) {48
46 case wds::CEA:49 MCS_DEBUG("dimensions: %dx%d@%d", rr.width, rr.height, rr.framerate);
47 switch (format.rate_resolution) {50
48 case wds::CEA640x480p60:51 // FIXME we don't support any other mode than extend for now as that means some
49 width = 640;52 // additional work from mir to still give us properly sized frames we can hand
50 height = 480;53 // to the encoder.
51 break;54 StreamConnector::DisplayOutput output{StreamConnector::DisplayMode::kExtend, rr.width, rr.height};
52 case wds::CEA720x480p60:55
53 case wds::CEA720x480i60:56 connector_ = mcs::mir::StreamConnector::Create(output);
54 width = 720;57 if (!connector_->IsValid())
55 height = 480;58 return false;
56 break;59
57 case wds::CEA720x576p50:60 encoder_ = mcs::android::H264Encoder::Create();
58 case wds::CEA720x576i50:61
59 width = 720;62 int profile = 0, level = 0, constraint = 0;
60 height = 576;63 mcs::video::ExtractProfileLevel(format_, &profile, &level, &constraint);
61 break;64
62 case wds::CEA1280x720p30:65 auto config = mcs::android::H264Encoder::DefaultConfiguration();
63 case wds::CEA1280x720p60:66 config.width = rr.width;
64 width = 1280;67 config.height = rr.height;
65 height = 720;68 config.framerate = rr.framerate;
66 break;69 config.profile_idc = profile;
67 case wds::CEA1920x1080p30:70 config.level_idc = level;
68 case wds::CEA1920x1080p60:71 config.constraint_set = constraint;
69 case wds::CEA1920x1080i60:72
70 width = 1920;73 if (!encoder_->Configure(config))
71 height = 1080;74 return false;
72 break;75
73 case wds::CEA1280x720p25:76 encoder_->Start();
74 case wds::CEA1280x720p50:77
75 case wds::CEA1280x720p24:78 renderer_ = mcs::mir::StreamRenderer::Create(connector_, encoder_);
76 width = 1280;79 renderer_->SetDimensions(rr.width, rr.height);
77 height = 720;80
78 break;81 sender_ = mcs::mir::MediaSender::Create(MediaSender::Endpoint{remote_address_, sink_port1_}, config);
79 case wds::CEA1920x1080p25:82 encoder_->SetDelegate(sender_);
80 case wds::CEA1920x1080p50:83
81 case wds::CEA1920x1080i50:84 return true;
82 case wds::CEA1920x1080p24:85}
83 width = 1920;86
84 height = 1080;87void SourceMediaManager::StartPipeline() {
85 break;88 sender_->Start();
86 default:89 encoder_->Start();
87 break;90 renderer_->StartThreaded();
88 }91}
89 break;92
90 default:93void SourceMediaManager::StopPipeline() {
91 break;94 renderer_->Stop();
92 }95 encoder_->Stop();
9396 sender_->Stop();
94 std::stringstream ss;97}
95 ss << "mirimagesrc mir-socket=/run/mir_socket ! videoconvert ! videoscale ! ";98
96 ss << Utils::Sprintf("video/x-raw,width=%d,height=%d ! ", width, height);99void SourceMediaManager::Play() {
97 ss << "videoflip method=counterclockwise ! queue2 ! video/x-raw,format=I420 ! ";100 if (!IsPaused() || !renderer_)
98 ss << "x264enc aud=false byte-stream=true tune=zerolatency ! ";101 return;
99 ss << Utils::Sprintf("video/x-h264,profile=%s ! ", profile.c_str());102
100 ss << "mpegtsmux ! rtpmp2tpay ! ";103 MCS_DEBUG("");
101 ss << Utils::Sprintf("udpsink name=sink host=%s port=%d", remote_address_.c_str(), sink_port1_);104
102105 StartPipeline();
103 GError *error = nullptr;106
104 GstElement *pipeline = gst_parse_launch(ss.str().c_str(), &error);107 state_ = State::Playing;
105 if (error) {108}
106 ERROR("Failed to setup GStreamer pipeline: %s", error->message);109
107 g_error_free(error);110void SourceMediaManager::Pause() {
108 return nullptr;111 if (IsPaused()|| !renderer_)
109 }112 return;
110113
111 return make_shared_gobject(pipeline);114 MCS_DEBUG("");
112}115
116 StopPipeline();
117
118 state_ = State::Paused;
119}
120
121void SourceMediaManager::Teardown() {
122 if (state_ == State::Stopped || !renderer_)
123 return;
124
125 MCS_DEBUG("");
126
127 StopPipeline();
128
129 state_ = State::Stopped;
130}
131
132bool SourceMediaManager::IsPaused() const {
133 return state_ == State::Paused ||
134 state_ == State::Stopped;
135}
136
137void SourceMediaManager::SendIDRPicture() {
138 if (!encoder_)
139 return;
140
141 encoder_->SendIDRFrame();
142}
143
144int SourceMediaManager::GetLocalRtpPort() const {
145 MCS_DEBUG("local port %d", sender_->LocalRTPPort());
146 return sender_->LocalRTPPort();
147}
148
149} // namespace mir
113} // namespace mcs150} // namespace mcs
114151
=== renamed file 'src/mcs/mirsourcemediamanager.h' => 'src/mcs/mir/sourcemediamanager.h'
--- src/mcs/mirsourcemediamanager.h 2015-11-30 10:41:56 +0000
+++ src/mcs/mir/sourcemediamanager.h 2016-02-25 12:47:02 +0000
@@ -15,22 +15,64 @@
15 *15 *
16 */16 */
1717
18#ifndef MIRMEDIAMANAGER_H_18#ifndef MCS_MIR_SOURCEMEDIAMANAGERNEXT_H_
19#define MIRMEDIAMANAGER_H_19#define MCS_MIR_SOURCEMEDIAMANAGERNEXT_H_
2020
21#include "gstsourcemediamanager.h"21#include <memory>
22
23#include "mcs/basesourcemediamanager.h"
24
25#include "mcs/video/baseencoder.h"
26
27#include "mcs/mir/streamconnector.h"
28#include "mcs/mir/streamrenderer.h"
29#include "mcs/mir/mediasender.h"
2230
23namespace mcs {31namespace mcs {
24class MirSourceMediaManager : public GstSourceMediaManager {32namespace mir {
33
34class SourceMediaManager : public mcs::BaseSourceMediaManager {
25public:35public:
26 explicit MirSourceMediaManager(const std::string &remote_address);36 typedef std::shared_ptr<SourceMediaManager> Ptr;
27 ~MirSourceMediaManager();37
38 enum class State {
39 Playing,
40 Paused,
41 Stopped
42 };
43
44 static Ptr Create(const std::string &remote_address);
45
46 ~SourceMediaManager();
47
48 void Play() override;
49 void Pause() override;
50 void Teardown() override;
51 bool IsPaused() const override;
52
53 void SendIDRPicture() override;
54
55 int GetLocalRtpPort() const override;
56
57private:
58 SourceMediaManager(const std::string &remote_address);
59
60 void StartPipeline();
61 void StopPipeline();
2862
29protected:63protected:
30 SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) override;64 bool Configure() override;
3165
32private:66private:
33 std::string remote_address_;67 std::string remote_address_;
68 State state_;
69 mcs::video::BaseEncoder::Ptr encoder_;
70 mcs::mir::StreamConnector::Ptr connector_;
71 mcs::mir::StreamRenderer::Ptr renderer_;
72 mcs::mir::MediaSender::Ptr sender_;
34};73};
74
75} // namespace mir
35} // namespace mcs76} // namespace mcs
77
36#endif78#endif
3779
=== added file 'src/mcs/mir/streamconnector.cpp'
--- src/mcs/mir/streamconnector.cpp 1970-01-01 00:00:00 +0000
+++ src/mcs/mir/streamconnector.cpp 2016-02-25 12:47:02 +0000
@@ -0,0 +1,204 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <boost/concept_check.hpp>
19
20#include "mcs/logger.h"
21#include "mcs/mir/streamconnector.h"
22
23namespace {
24static constexpr const char *kMirSocket{"/run/mir_socket"};
25static constexpr const char *kMirConnectionName{"aethercast screencast client"};
26}
27
28namespace mcs {
29namespace mir {
30
31std::string StreamConnector::DisplayModeToString(const DisplayMode &mode) {
32 switch (mode) {
33 case DisplayMode::kExtend:
34 return "extend";
35 case DisplayMode::kMirror:
36 return "mirror";
37 default:
38 break;
39 }
40 return "unknown";
41}
42
43StreamConnector::Ptr StreamConnector::Create(const StreamConnector::DisplayOutput &output) {
44 return std::shared_ptr<StreamConnector>(new StreamConnector(output));
45}
46
47StreamConnector::StreamConnector(const StreamConnector::DisplayOutput &output) :
48 output_(output) {
49 connection_ = mir_connect_sync(kMirSocket, kMirConnectionName);
50 if (!mir_connection_is_valid(connection_)) {
51 MCS_ERROR("Failed to connect to Mir server: %s",
52 mir_connection_get_error_message(connection_));
53 return;
54 }
55
56 auto config = mir_connection_create_display_config(connection_);
57
58 MirDisplayOutput *active_output = nullptr;
59 int output_index = 0;
60
61 for (unsigned int i = 0; i < config->num_outputs; ++i) {
62 if (config->outputs[i].connected &&
63 config->outputs[i].used &&
64 config->outputs[i].current_mode < config->outputs[i].num_modes) {
65 // Found an active connection we can just use for our purpose
66 active_output = &config->outputs[i];
67 output_index = i;
68 break;
69 }
70 }
71
72 if (!active_output) {
73 MCS_ERROR("Failed to find a suitable display output");
74 return;
75 }
76
77 const MirDisplayMode *display_mode = &active_output->modes[active_output->current_mode];
78
79 params_.height = display_mode->vertical_resolution;
80 params_.width = display_mode->horizontal_resolution;
81
82 if (output_.mode == DisplayMode::kMirror) {
83 params_.region.left = 0;
84 params_.region.top = 0;
85 params_.region.width = params_.width;
86 params_.region.height = params_.height;
87
88 output_.width = params_.width;
89 output_.height = params_.height;
90 }
91 else if (output_.mode == DisplayMode::kExtend) {
92 // If we request a screen region outside the available screen area
93 // mir will create a mir output which is then available for everyone
94 // as just another display.
95 params_.region.left = params_.width;
96 params_.region.top = 0;
97 params_.region.width = output_.width;
98 params_.region.height = output_.height;
99
100 params_.width = output_.width;
101 params_.height = output_.height;
102 }
103
104 output_.refresh_rate = display_mode->refresh_rate;
105
106 MCS_INFO("Selected output ID %i [(%ix%i)+(%ix%i)] orientation %d",
107 output_index,
108 params_.width, params_.height,
109 params_.region.left, params_.region.top,
110 active_output->orientation);
111
112 MCS_DEBUG("Setting up screencast [%s %dx%d]",
113 DisplayModeToString(output_.mode),
114 output_.width,
115 output_.height);
116
117 unsigned int num_pixel_formats = 0;
118 mir_connection_get_available_surface_formats(connection_, &params_.pixel_format,
119 1, &num_pixel_formats);
120 if (num_pixel_formats == 0) {
121 MCS_ERROR("Failed to find suitable pixel format: %s",
122 mir_connection_get_error_message(connection_));
123 return;
124 }
125
126 screencast_ = mir_connection_create_screencast_sync(connection_, &params_);
127 if (!screencast_) {
128 MCS_ERROR("Failed to create Mir screencast: %s",
129 mir_connection_get_error_message(connection_));
130 return;
131 }
132
133 buffer_stream_ = mir_screencast_get_buffer_stream(screencast_);
134 if (!buffer_stream_) {
135 MCS_ERROR("Failed to setup Mir buffer stream");
136 return;
137 }
138
139 auto platform_type = mir_buffer_stream_get_platform_type(buffer_stream_);
140 if (platform_type != mir_platform_type_android) {
141 MCS_ERROR("Not running with android platform: This is not supported.");
142 mir_buffer_stream_release_sync(buffer_stream_);
143 buffer_stream_ = nullptr;
144 return;
145 }
146}
147
148StreamConnector::~StreamConnector() {
149 if (screencast_)
150 mir_screencast_release_sync(screencast_);
151
152 if (connection_)
153 mir_connection_release(connection_);
154}
155
156void StreamConnector::SwapBuffersSync() {
157 if (!buffer_stream_)
158 return;
159
160 mir_buffer_stream_swap_buffers_sync(buffer_stream_);
161}
162
163void StreamConnector::SwapBuffers() {
164 if (!buffer_stream_)
165 return;
166
167 mir_buffer_stream_swap_buffers(buffer_stream_, [](MirBufferStream *stream, void *client_context) {
168 boost::ignore_unused_variable_warning(stream);
169 boost::ignore_unused_variable_warning(client_context);
170
171 MCS_DEBUG("Buffers are swapped now");
172
173 }, nullptr);
174}
175
176bool StreamConnector::IsValid() const {
177 return connection_ && screencast_ && buffer_stream_;
178}
179
180void* StreamConnector::NativeWindowHandle() const {
181 if (!buffer_stream_)
182 return nullptr;
183
184 return reinterpret_cast<void*>(mir_buffer_stream_get_egl_native_window(buffer_stream_));
185}
186
187void* StreamConnector::NativeDisplayHandle() const {
188 if (!connection_)
189 return nullptr;
190
191 return mir_connection_get_egl_native_display(connection_);
192}
193
194StreamConnector::DisplayOutput StreamConnector::OutputMode() const {
195 return output_;
196}
197
198MirNativeBuffer* StreamConnector::CurrentBuffer() const {
199 MirNativeBuffer *buffer = nullptr;
200 mir_buffer_stream_get_current_buffer(buffer_stream_, &buffer);
201 return buffer;
202}
203} // namespace mir
204} // namespace mcs
0205
=== added file 'src/mcs/mir/streamconnector.h'
--- src/mcs/mir/streamconnector.h 1970-01-01 00:00:00 +0000
+++ src/mcs/mir/streamconnector.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,77 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MCS_MIR_CONNECTOR_H_
19#define MCS_MIR_CONNECTOR_H_
20
21#include <memory>
22
23#include <mir_toolkit/mir_client_library.h>
24#include <mir_toolkit/mir_screencast.h>
25#include <mir_toolkit/mir_buffer_stream.h>
26
27namespace mcs {
28namespace mir {
29
30class StreamConnector {
31public:
32 typedef std::shared_ptr<StreamConnector> Ptr;
33
34 enum class DisplayMode {
35 kMirror,
36 kExtend
37 };
38
39 static std::string DisplayModeToString(const DisplayMode &mode);
40
41 struct DisplayOutput {
42 DisplayMode mode;
43 unsigned int width;
44 unsigned int height;
45 double refresh_rate;
46 };
47
48 static Ptr Create(const DisplayOutput &output);
49
50 ~StreamConnector();
51
52 void SwapBuffers();
53 void SwapBuffersSync();
54
55 bool IsValid() const;
56
57 void* NativeWindowHandle() const;
58 void* NativeDisplayHandle() const;
59
60 DisplayOutput OutputMode() const;
61 MirNativeBuffer* CurrentBuffer() const;
62
63private:
64 StreamConnector(const DisplayOutput &output);
65
66private:
67 MirConnection *connection_;
68 MirScreencast *screencast_;
69 MirBufferStream *buffer_stream_;
70 MirScreencastParameters params_;
71 DisplayOutput output_;
72};
73
74} // namespace mir
75} // namespace mcs
76
77#endif
078
=== added file 'src/mcs/mir/streamrenderer.cpp'
--- src/mcs/mir/streamrenderer.cpp 1970-01-01 00:00:00 +0000
+++ src/mcs/mir/streamrenderer.cpp 2016-02-25 12:47:02 +0000
@@ -0,0 +1,175 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#define GL_GLEXT_PROTOTYPES
19#define EGL_EGLEXT_PROTOTYPES
20#include <EGL/egl.h>
21#include <EGL/eglext.h>
22#include <GLES2/gl2.h>
23#include <GLES2/gl2ext.h>
24
25#include <system/window.h>
26
27#include <chrono>
28#include <thread>
29
30#include <boost/concept_check.hpp>
31
32#include "mcs/logger.h"
33
34#include "mcs/video/statistics.h"
35
36#include "mcs/mir/streamconnector.h"
37#include "mcs/mir/streamrenderer.h"
38
39namespace {
40static constexpr const char *kStreamRendererThreadName{"StreamRenderer"};
41static constexpr unsigned int kNumBufferSlots{2};
42}
43
44namespace mcs {
45namespace mir {
46
47StreamRenderer::Ptr StreamRenderer::Create(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder) {
48 return std::shared_ptr<StreamRenderer>(new StreamRenderer(connector, encoder));
49}
50
51StreamRenderer::StreamRenderer(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder) :
52 connector_(connector),
53 encoder_(encoder),
54 running_(false),
55 width_(0),
56 height_(0),
57 input_buffers_(mcs::video::BufferQueue::Create(kNumBufferSlots)) {
58}
59
60StreamRenderer::~StreamRenderer() {
61 Stop();
62}
63
64void StreamRenderer::RenderThread() {
65 MCS_DEBUG("Everything successfully setup; Starting recording now %dx%d@%d",
66 width_, height_, encoder_->Configuration().framerate);
67
68 bool waiting = false;
69 mcs::TimestampUs wait_slot_time;
70
71 static int64_t start_time_us = mcs::Utils::GetNowUs();
72 static unsigned int frame_count = 0;
73 static const mcs::TimestampUs target_iteration_time = (1. / encoder_->Configuration().framerate) * 1000000ll;
74
75 while (running_) {
76 if (!waiting)
77 wait_slot_time = mcs::Utils::GetNowUs();
78
79 mcs::TimestampUs iteration_start_time = mcs::Utils::GetNowUs();
80
81 if (!input_buffers_->WaitForSlots()) {
82 waiting = true;
83 continue;
84 }
85
86 waiting = false;
87
88 int64_t wait_time = (mcs::Utils::GetNowUs() - wait_slot_time) / 1000ll;
89 video::Statistics::Instance()->RecordRendererWait(wait_time);
90
91 mcs::TimestampUs before_swap = mcs::Utils::GetNowUs();
92
93 // This will trigger the rendering/compositing process inside mir
94 // and will block until that is done and we received a new buffer
95 connector_->SwapBuffersSync();
96
97 int64_t swap_time = (mcs::Utils::GetNowUs() - before_swap) / 1000ll;
98 video::Statistics::Instance()->RecordRendererSwapped(swap_time);
99
100 auto native_buffer = connector_->CurrentBuffer();
101
102 auto buffer = mcs::video::Buffer::Create(native_buffer);
103 buffer->SetDelegate(shared_from_this());
104
105 frame_count++;
106 int64_t time_now_us = mcs::Utils::GetNowUs();
107 if (start_time_us + 1000000ll <= time_now_us) {
108 video::Statistics::Instance()->RecordRendererFramesPerSecond(frame_count);
109 frame_count = 0;
110 start_time_us = time_now_us;
111 }
112
113 // FIXME: at optimum we would get the timestamp directly supplied
114 // from mir but as long as that isn't available we don't have any
115 // other chance and need to do it here.
116 buffer->SetTimestamp(mcs::Utils::GetNowUs());
117
118 input_buffers_->Push(buffer);
119
120 encoder_->QueueBuffer(buffer);
121
122 static mcs::TimestampUs last_queued_time = mcs::Utils::GetNowUs();
123 int64_t renderer_iteration_time = (mcs::Utils::GetNowUs() - last_queued_time) / 1000ll;
124 last_queued_time = mcs::Utils::GetNowUs();
125 video::Statistics::Instance()->RecordRendererIteration(renderer_iteration_time);
126
127 mcs::TimestampUs iteration_time = mcs::Utils::GetNowUs() - iteration_start_time;
128 int64_t sleep_time = target_iteration_time - iteration_time;
129 if (sleep_time > 0)
130 std::this_thread::sleep_for(std::chrono::microseconds(sleep_time));
131 }
132}
133
134void StreamRenderer::OnBufferFinished(const video::Buffer::Ptr &buffer) {
135 boost::ignore_unused_variable_warning(buffer);
136
137 // We're currently relying on the buffers to come back in order so
138 // we can safely remove the head from the queue here which then
139 // gives us a free slot at the beginning which will be filled by
140 // the renderer again.
141 input_buffers_->Pop();
142}
143
144void StreamRenderer::SetDimensions(unsigned int width, unsigned int height) {
145 width_ = width;
146 height_ = height;
147}
148
149void StreamRenderer::StartThreaded() {
150 if (running_)
151 return;
152
153 auto output_mode = connector_->OutputMode();
154
155 if (width_ == 0 || height_ == 0) {
156 width_ = output_mode.width;
157 height_ = output_mode.height;
158 }
159
160 running_ = true;
161
162 render_thread_ = std::thread(&StreamRenderer::RenderThread, this);
163 pthread_setname_np(render_thread_.native_handle(), kStreamRendererThreadName);
164}
165
166void StreamRenderer::Stop() {
167 if (!running_)
168 return;
169
170 running_ = false;
171 render_thread_.join();
172}
173
174} // namespace mir
175} // namespace mcs
0176
=== added file 'src/mcs/mir/streamrenderer.h'
--- src/mcs/mir/streamrenderer.h 1970-01-01 00:00:00 +0000
+++ src/mcs/mir/streamrenderer.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,69 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef MCS_MIR_STREAMRENDERER_H_
19#define MCS_MIR_STREAMRENDERER_H_
20
21#include <memory>
22#include <thread>
23#include <mutex>
24#include <queue>
25
26#include "mcs/mir/streamrenderer.h"
27#include "mcs/mir/streamconnector.h"
28
29#include "mcs/video/baseencoder.h"
30#include "mcs/video/bufferqueue.h"
31
32namespace mcs {
33namespace mir {
34class StreamRenderer : public std::enable_shared_from_this<StreamRenderer>,
35 public mcs::video::Buffer::Delegate {
36public:
37 static constexpr unsigned int kNumTextures{2};
38
39 typedef std::shared_ptr<StreamRenderer> Ptr;
40
41 static Ptr Create(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder);
42
43 ~StreamRenderer();
44
45 void SetDimensions(unsigned int width, unsigned int height);
46
47 void StartThreaded();
48 void Stop();
49
50 void OnBufferFinished(const mcs::video::Buffer::Ptr &buffer);
51
52private:
53 StreamRenderer(const StreamConnector::Ptr &connector, const video::BaseEncoder::Ptr &encoder);
54
55 void RenderThread();
56
57private:
58 StreamConnector::Ptr connector_;
59 video::BaseEncoder::Ptr encoder_;
60 std::thread render_thread_;
61 bool running_;
62 unsigned int width_;
63 unsigned int height_;
64 mcs::video::BufferQueue::Ptr input_buffers_;
65};
66} // namespace mir
67} // namespace mcs
68
69#endif
070
=== modified file 'src/mcs/miracastcontroller.h'
--- src/mcs/miracastcontroller.h 2016-01-21 13:25:31 +0000
+++ src/mcs/miracastcontroller.h 2016-02-25 12:47:02 +0000
@@ -52,7 +52,9 @@
52 virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;52 virtual void Connect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;
53 virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;53 virtual void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback) = 0;
5454
55 virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;55 virtual void DisconnectAll(ResultCallback callback) = 0;
56
57 virtual mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;
5658
57 virtual NetworkDeviceState State() const = 0;59 virtual NetworkDeviceState State() const = 0;
58 virtual std::vector<NetworkManager::Capability> Capabilities() const = 0;60 virtual std::vector<NetworkManager::Capability> Capabilities() const = 0;
5961
=== modified file 'src/mcs/miracastcontrollerskeleton.cpp'
--- src/mcs/miracastcontrollerskeleton.cpp 2016-01-21 13:25:31 +0000
+++ src/mcs/miracastcontrollerskeleton.cpp 2016-02-25 12:47:02 +0000
@@ -119,6 +119,10 @@
119 G_CALLBACK(&MiracastControllerSkeleton::OnHandleScan), new WeakKeepAlive<MiracastControllerSkeleton>(inst),119 G_CALLBACK(&MiracastControllerSkeleton::OnHandleScan), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
120 [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));120 [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
121121
122 g_signal_connect_data(inst->manager_obj_.get(), "handle-disconnect-all",
123 G_CALLBACK(&MiracastControllerSkeleton::OnHandleDisconnectAll), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
124 [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
125
122 inst->SyncProperties();126 inst->SyncProperties();
123127
124 g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(inst->manager_obj_.get()),128 g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(inst->manager_obj_.get()),
@@ -142,13 +146,43 @@
142146
143 INFO("Scanning for remote devices");147 INFO("Scanning for remote devices");
144148
145 inst->Scan();149 auto error = inst->Scan();
150 if (error != mcs::Error::kNone) {
151 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s", mcs::ErrorToString(error).c_str());
152 return TRUE;
153 }
146154
147 g_dbus_method_invocation_return_value(invocation, nullptr);155 g_dbus_method_invocation_return_value(invocation, nullptr);
148156
149 return TRUE;157 return TRUE;
150}158}
151159
160gboolean MiracastControllerSkeleton::OnHandleDisconnectAll(AethercastInterfaceManager *skeleton,
161 GDBusMethodInvocation *invocation, gpointer user_data) {
162 boost::ignore_unused_variable_warning(skeleton);
163 auto inst = static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(user_data)->GetInstance().lock();
164
165 if (not inst) {
166 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
167 return TRUE;
168 }
169
170 g_object_ref(invocation);
171 auto inv = make_shared_gobject(invocation);
172
173 inst->DisconnectAll([inv](mcs::Error error) {
174 if (error != Error::kNone) {
175 g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
176 "%s", mcs::ErrorToString(error).c_str());
177 return;
178 }
179
180 g_dbus_method_invocation_return_value(inv.get(), nullptr);
181 });
182
183 return TRUE;
184}
185
152std::shared_ptr<MiracastControllerSkeleton> MiracastControllerSkeleton::FinalizeConstruction() {186std::shared_ptr<MiracastControllerSkeleton> MiracastControllerSkeleton::FinalizeConstruction() {
153 auto sp = shared_from_this();187 auto sp = shared_from_this();
154188
155189
=== modified file 'src/mcs/miracastcontrollerskeleton.h'
--- src/mcs/miracastcontrollerskeleton.h 2015-12-21 15:20:11 +0000
+++ src/mcs/miracastcontrollerskeleton.h 2016-02-25 12:47:02 +0000
@@ -58,6 +58,8 @@
5858
59 static gboolean OnHandleScan(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,59 static gboolean OnHandleScan(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
60 gpointer user_data);60 gpointer user_data);
61 static gboolean OnHandleDisconnectAll(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
62 gpointer user_data);
6163
62 MiracastControllerSkeleton(const std::shared_ptr<MiracastController> &controller);64 MiracastControllerSkeleton(const std::shared_ptr<MiracastController> &controller);
63 std::shared_ptr<MiracastControllerSkeleton> FinalizeConstruction();65 std::shared_ptr<MiracastControllerSkeleton> FinalizeConstruction();
6466
=== modified file 'src/mcs/miracastservice.cpp'
--- src/mcs/miracastservice.cpp 2016-01-21 13:25:31 +0000
+++ src/mcs/miracastservice.cpp 2016-02-25 12:47:02 +0000
@@ -20,6 +20,9 @@
20#include <cstdint>20#include <cstdint>
2121
22#include <sys/prctl.h>22#include <sys/prctl.h>
23#include <signal.h>
24#include <sys/time.h>
25#include <sys/resource.h>
2326
24#include <glib.h>27#include <glib.h>
25#include <glib-unix.h>28#include <glib-unix.h>
@@ -31,6 +34,7 @@
3134
32#include <wds/logging.h>35#include <wds/logging.h>
3336
37#include "initgstreameronce.h"
34#include "config.h"38#include "config.h"
35#include "keep_alive.h"39#include "keep_alive.h"
36#include "logger.h"40#include "logger.h"
@@ -45,6 +49,7 @@
45const std::uint16_t kMiracastDefaultRtspCtrlPort{7236};49const std::uint16_t kMiracastDefaultRtspCtrlPort{7236};
46const std::chrono::milliseconds kStateIdleTimeout{5000};50const std::chrono::milliseconds kStateIdleTimeout{5000};
47const std::chrono::seconds kShutdownGracePreriod{1};51const std::chrono::seconds kShutdownGracePreriod{1};
52const std::int16_t kProcessPriorityUrgentDisplay{-8};
4853
49// SafeLog serves as integration point to the wds::LogSystem world.54// SafeLog serves as integration point to the wds::LogSystem world.
50template <mcs::Logger::Severity severity>55template <mcs::Logger::Severity severity>
@@ -94,6 +99,9 @@
94 return 0;99 return 0;
95 }100 }
96101
102 if (options.debug)
103 mcs::Log().Init(mcs::Logger::Severity::kDebug);
104
97 struct Runtime {105 struct Runtime {
98 static gboolean OnSignalRaised(gpointer user_data) {106 static gboolean OnSignalRaised(gpointer user_data) {
99 auto thiz = static_cast<Runtime*>(user_data);107 auto thiz = static_cast<Runtime*>(user_data);
@@ -122,6 +130,9 @@
122 g_unix_signal_add(SIGINT, OnSignalRaised, this);130 g_unix_signal_add(SIGINT, OnSignalRaised, this);
123 g_unix_signal_add(SIGTERM, OnSignalRaised, this);131 g_unix_signal_add(SIGTERM, OnSignalRaised, this);
124132
133 // Initialize gstreamer.
134 mcs::InitGstreamerOnceOrThrow();
135
125 // Redirect all wds logging to our own.136 // Redirect all wds logging to our own.
126 wds::LogSystem::set_vlog_func(SafeLog<mcs::Logger::Severity::kTrace>);137 wds::LogSystem::set_vlog_func(SafeLog<mcs::Logger::Severity::kTrace>);
127 wds::LogSystem::set_log_func(SafeLog<mcs::Logger::Severity::kInfo>);138 wds::LogSystem::set_log_func(SafeLog<mcs::Logger::Severity::kInfo>);
@@ -156,6 +167,9 @@
156 if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)167 if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
157 g_warning("Failed to make us a subreaper of our children");168 g_warning("Failed to make us a subreaper of our children");
158169
170 // Raise our process priority to be as fast as possible
171 setpriority(PRIO_PROCESS, 0, kProcessPriorityUrgentDisplay);
172
159 network_manager = mcs::NetworkManagerFactory::Create();173 network_manager = mcs::NetworkManagerFactory::Create();
160 service = mcs::MiracastService::Create(network_manager);174 service = mcs::MiracastService::Create(network_manager);
161 mcsa = mcs::MiracastControllerSkeleton::create(service);175 mcsa = mcs::MiracastControllerSkeleton::create(service);
@@ -202,6 +216,8 @@
202 network_manager_->Setup();216 network_manager_->Setup();
203 }217 }
204218
219 system_controller_ = mcs::SystemController::CreatePlatformDefault();
220
205 return shared_from_this();221 return shared_from_this();
206}222}
207223
@@ -246,8 +262,6 @@
246}262}
247263
248void MiracastService::AdvanceState(NetworkDeviceState new_state) {264void MiracastService::AdvanceState(NetworkDeviceState new_state) {
249 IpV4Address address;
250
251 DEBUG("new state %s current state %s",265 DEBUG("new state %s current state %s",
252 mcs::NetworkDevice::StateToStr(new_state),266 mcs::NetworkDevice::StateToStr(new_state),
253 mcs::NetworkDevice::StateToStr(current_state_));267 mcs::NetworkDevice::StateToStr(current_state_));
@@ -256,13 +270,12 @@
256 case kAssociation:270 case kAssociation:
257 break;271 break;
258272
273 case kConfiguration:
274 break;
275
259 case kConnected:276 case kConnected:
260 address = network_manager_->LocalAddress();277 source_ = MiracastSourceManager::Create(network_manager_->LocalAddress(), kMiracastDefaultRtspCtrlPort);
261
262 source_ = MiracastSourceManager::Create(address, kMiracastDefaultRtspCtrlPort);
263
264 FinishConnectAttempt();278 FinishConnectAttempt();
265
266 break;279 break;
267280
268 case kFailure:281 case kFailure:
@@ -272,6 +285,8 @@
272 source_.reset();285 source_.reset();
273 current_device_.reset();286 current_device_.reset();
274287
288 system_controller_->DisplayStateLock()->Release(mcs::DisplayState::On);
289
275 StartIdleTimer();290 StartIdleTimer();
276 break;291 break;
277292
@@ -359,6 +374,8 @@
359 return;374 return;
360 }375 }
361376
377 system_controller_->DisplayStateLock()->Acquire(mcs::DisplayState::On);
378
362 current_device_ = device;379 current_device_ = device;
363 connect_callback_ = callback;380 connect_callback_ = callback;
364}381}
@@ -377,8 +394,17 @@
377 callback(Error::kNone);394 callback(Error::kNone);
378}395}
379396
380void MiracastService::Scan(const std::chrono::seconds &timeout) {397void MiracastService::DisconnectAll(ResultCallback callback) {
398 Disconnect(current_device_, callback);
399}
400
401mcs::Error MiracastService::Scan(const std::chrono::seconds &timeout) {
402 if (current_device_)
403 return mcs::Error::kInvalidState;
404
381 network_manager_->Scan(timeout);405 network_manager_->Scan(timeout);
406
407 return mcs::Error::kNone;
382}408}
383409
384void MiracastService::Shutdown() {410void MiracastService::Shutdown() {
385411
=== modified file 'src/mcs/miracastservice.h'
--- src/mcs/miracastservice.h 2016-01-21 13:25:31 +0000
+++ src/mcs/miracastservice.h 2016-02-25 12:47:02 +0000
@@ -32,6 +32,7 @@
32#include "networkdevice.h"32#include "networkdevice.h"
33#include "non_copyable.h"33#include "non_copyable.h"
34#include "types.h"34#include "types.h"
35#include "systemcontroller.h"
3536
36namespace mcs {37namespace mcs {
37class MiracastService : public MiracastController,38class MiracastService : public MiracastController,
@@ -64,7 +65,9 @@
64 void Connect(const NetworkDevice::Ptr &device, ResultCallback callback);65 void Connect(const NetworkDevice::Ptr &device, ResultCallback callback);
65 void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback);66 void Disconnect(const NetworkDevice::Ptr &device, ResultCallback callback);
6667
67 void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30});68 void DisconnectAll(ResultCallback callback);
69
70 mcs::Error Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30});
6871
69 NetworkDeviceState State() const;72 NetworkDeviceState State() const;
70 std::vector<NetworkManager::Capability> Capabilities() const;73 std::vector<NetworkManager::Capability> Capabilities() const;
@@ -104,6 +107,7 @@
104 guint scan_timeout_source_;107 guint scan_timeout_source_;
105 ResultCallback current_scan_callback_;108 ResultCallback current_scan_callback_;
106 std::vector<NetworkDeviceRole> supported_roles_;109 std::vector<NetworkDeviceRole> supported_roles_;
110 mcs::SystemController::Ptr system_controller_;
107};111};
108} // namespace mcs112} // namespace mcs
109#endif113#endif
110114
=== modified file 'src/mcs/miracastsourceclient.cpp'
--- src/mcs/miracastsourceclient.cpp 2015-12-09 16:07:13 +0000
+++ src/mcs/miracastsourceclient.cpp 2016-02-25 12:47:02 +0000
@@ -25,7 +25,7 @@
25#include "keep_alive.h"25#include "keep_alive.h"
26#include "logger.h"26#include "logger.h"
27#include "miracastsourceclient.h"27#include "miracastsourceclient.h"
28#include "mirsourcemediamanager.h"28#include "mcs/mir/sourcemediamanager.h"
29#include "testsourcemediamanager.h"29#include "testsourcemediamanager.h"
30#include "mediamanagerfactory.h"30#include "mediamanagerfactory.h"
3131
@@ -34,14 +34,15 @@
34#include "logging.h"34#include "logging.h"
3535
36namespace mcs {36namespace mcs {
37std::shared_ptr<MiracastSourceClient> MiracastSourceClient::Create(ScopedGObject<GSocket>&& socket) {37std::shared_ptr<MiracastSourceClient> MiracastSourceClient::Create(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address) {
38 std::shared_ptr<MiracastSourceClient> sp{new MiracastSourceClient{std::move(socket)}};38 std::shared_ptr<MiracastSourceClient> sp{new MiracastSourceClient{std::move(socket), local_address}};
39 return sp->FinalizeConstruction();39 return sp->FinalizeConstruction();
40}40}
4141
42MiracastSourceClient::MiracastSourceClient(ScopedGObject<GSocket>&& socket) :42MiracastSourceClient::MiracastSourceClient(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address) :
43 socket_(std::move(socket)),43 socket_(std::move(socket)),
44 socket_source_(0) {44 socket_source_(0),
45 local_address_(local_address) {
45}46}
4647
47MiracastSourceClient::~MiracastSourceClient() {48MiracastSourceClient::~MiracastSourceClient() {
@@ -82,7 +83,15 @@
82}83}
8384
84std::string MiracastSourceClient::GetLocalIPAddress() const {85std::string MiracastSourceClient::GetLocalIPAddress() const {
85 return local_address_;86 return local_address_.to_string();
87}
88
89int MiracastSourceClient::GetNextCSeq(int *initial_peer_cseq) const {
90 static int send_cseq = 0;
91 ++send_cseq;
92 if (initial_peer_cseq && send_cseq == *initial_peer_cseq)
93 send_cseq *= 2;
94 return send_cseq;
86}95}
8796
88class TimerCallbackData {97class TimerCallbackData {
8998
=== modified file 'src/mcs/miracastsourceclient.h'
--- src/mcs/miracastsourceclient.h 2015-12-07 09:07:50 +0000
+++ src/mcs/miracastsourceclient.h 2016-02-25 12:47:02 +0000
@@ -31,8 +31,9 @@
31#include <wds/source.h>31#include <wds/source.h>
32#include <wds/media_manager.h>32#include <wds/media_manager.h>
3333
34#include "non_copyable.h"34#include "mcs/ip_v4_address.h"
35#include "scoped_gobject.h"35#include "mcs/non_copyable.h"
36#include "mcs/scoped_gobject.h"
3637
37namespace mcs {38namespace mcs {
38class TimerCallbackData;39class TimerCallbackData;
@@ -45,7 +46,7 @@
45 virtual void OnConnectionClosed() = 0;46 virtual void OnConnectionClosed() = 0;
46 };47 };
4748
48 static std::shared_ptr<MiracastSourceClient> Create(ScopedGObject<GSocket>&& socket);49 static std::shared_ptr<MiracastSourceClient> Create(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address);
4950
50 ~MiracastSourceClient();51 ~MiracastSourceClient();
5152
@@ -57,6 +58,7 @@
57 std::string GetLocalIPAddress() const override;58 std::string GetLocalIPAddress() const override;
58 uint CreateTimer(int seconds) override;59 uint CreateTimer(int seconds) override;
59 void ReleaseTimer(uint timerId) override;60 void ReleaseTimer(uint timerId) override;
61 int GetNextCSeq(int* initial_peer_cseq = nullptr) const override;
6062
61public:63public:
62 static gboolean OnTimeout(gpointer user_data);64 static gboolean OnTimeout(gpointer user_data);
@@ -65,7 +67,7 @@
65 gpointer user_data);67 gpointer user_data);
6668
67private:69private:
68 MiracastSourceClient(ScopedGObject<GSocket>&& socket);70 MiracastSourceClient(ScopedGObject<GSocket>&& socket, const mcs::IpV4Address &local_address);
69 std::shared_ptr<MiracastSourceClient> FinalizeConstruction();71 std::shared_ptr<MiracastSourceClient> FinalizeConstruction();
7072
71 void DumpRtsp(const std::string &prefix, const std::string &data);73 void DumpRtsp(const std::string &prefix, const std::string &data);
@@ -75,7 +77,7 @@
75 std::weak_ptr<Delegate> delegate_;77 std::weak_ptr<Delegate> delegate_;
76 ScopedGObject<GSocket> socket_;78 ScopedGObject<GSocket> socket_;
77 guint socket_source_;79 guint socket_source_;
78 std::string local_address_;80 mcs::IpV4Address local_address_;
79 std::vector<guint> timers_;81 std::vector<guint> timers_;
80 std::unique_ptr<wds::Source> source_;82 std::unique_ptr<wds::Source> source_;
81 std::shared_ptr<wds::SourceMediaManager> media_manager_;83 std::shared_ptr<wds::SourceMediaManager> media_manager_;
8284
=== modified file 'src/mcs/miracastsourcemanager.cpp'
--- src/mcs/miracastsourcemanager.cpp 2016-01-16 13:40:27 +0000
+++ src/mcs/miracastsourcemanager.cpp 2016-02-25 12:47:02 +0000
@@ -22,7 +22,7 @@
22#include "logging.h"22#include "logging.h"
2323
24namespace mcs {24namespace mcs {
25std::shared_ptr<MiracastSourceManager> MiracastSourceManager::Create(const IpV4Address &address, unsigned short port) {25std::shared_ptr<MiracastSourceManager> MiracastSourceManager::Create(const mcs::IpV4Address &address, unsigned short port) {
26 auto sp = std::shared_ptr<MiracastSourceManager>{new MiracastSourceManager{}};26 auto sp = std::shared_ptr<MiracastSourceManager>{new MiracastSourceManager{}};
27 sp->Setup(address, port);27 sp->Setup(address, port);
28 return sp;28 return sp;
@@ -49,7 +49,7 @@
49 delegate_.reset();49 delegate_.reset();
50}50}
5151
52bool MiracastSourceManager::Setup(const IpV4Address &address, unsigned short port) {52bool MiracastSourceManager::Setup(const mcs::IpV4Address &address, unsigned short port) {
53 GError *error = nullptr;53 GError *error = nullptr;
5454
55 if (socket_)55 if (socket_)
@@ -97,8 +97,9 @@
9797
98 g_source_unref(source);98 g_source_unref(source);
9999
100 DEBUG("Successfully setup source on %s:%d and awaiting incoming connection requests",100 DEBUG("Successfully setup source on %s:%d and awaiting incoming connection requests", address.to_string(), port);
101 address.to_string(), port);101
102 local_address_ = address;
102103
103 socket_.swap(socket);104 socket_.swap(socket);
104105
@@ -132,7 +133,7 @@
132 return TRUE;133 return TRUE;
133 }134 }
134135
135 inst->active_sink_ = MiracastSourceClient::Create(ScopedGObject<GSocket>{client_socket});136 inst->active_sink_ = MiracastSourceClient::Create(ScopedGObject<GSocket>{client_socket}, inst->local_address_);
136 inst->active_sink_->SetDelegate(inst->shared_from_this());137 inst->active_sink_->SetDelegate(inst->shared_from_this());
137138
138 return TRUE;139 return TRUE;
139140
=== modified file 'src/mcs/miracastsourcemanager.h'
--- src/mcs/miracastsourcemanager.h 2015-12-09 16:07:13 +0000
+++ src/mcs/miracastsourcemanager.h 2016-02-25 12:47:02 +0000
@@ -41,7 +41,7 @@
41 Delegate() = default;41 Delegate() = default;
42 };42 };
4343
44 static std::shared_ptr<MiracastSourceManager> Create(const IpV4Address &address, unsigned short port);44 static std::shared_ptr<MiracastSourceManager> Create(const mcs::IpV4Address &address, unsigned short port);
4545
46 ~MiracastSourceManager();46 ~MiracastSourceManager();
4747
@@ -56,13 +56,14 @@
5656
57 MiracastSourceManager();57 MiracastSourceManager();
5858
59 bool Setup(const IpV4Address &address, unsigned short port);59 bool Setup(const mcs::IpV4Address &address, unsigned short port);
6060
61private:61private:
62 std::weak_ptr<Delegate> delegate_;62 std::weak_ptr<Delegate> delegate_;
63 ScopedGObject<GSocket> socket_;63 ScopedGObject<GSocket> socket_;
64 guint socket_source_;64 guint socket_source_;
65 std::shared_ptr<MiracastSourceClient> active_sink_;65 std::shared_ptr<MiracastSourceClient> active_sink_;
66 mcs::IpV4Address local_address_;
66};67};
67} // namespace mcs68} // namespace mcs
68#endif69#endif
6970
=== removed file 'src/mcs/networkdeviceskeleton.cpp'
--- src/mcs/networkdeviceskeleton.cpp 2016-01-21 13:25:31 +0000
+++ src/mcs/networkdeviceskeleton.cpp 1970-01-01 00:00:00 +0000
@@ -1,142 +0,0 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <algorithm>
19#include <boost/concept_check.hpp>
20
21#include "networkdeviceskeleton.h"
22#include "utils.h"
23#include "keep_alive.h"
24#include "logger.h"
25#include "dbushelpers.h"
26
27namespace mcs {
28
29NetworkDeviceSkeleton::Ptr NetworkDeviceSkeleton::Create(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) {
30 return std::shared_ptr<NetworkDeviceSkeleton>(new NetworkDeviceSkeleton(connection, path, device, controller))->FinalizeConstruction();
31}
32
33NetworkDeviceSkeleton::NetworkDeviceSkeleton(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) :
34 ForwardingNetworkDevice(device),
35 connection_(connection),
36 object_(make_shared_gobject(aethercast_interface_object_skeleton_new(path.c_str()))),
37 path_(path),
38 controller_(controller),
39 device_iface_(aethercast_interface_device_skeleton_new()) {
40}
41
42std::shared_ptr<NetworkDeviceSkeleton> NetworkDeviceSkeleton::FinalizeConstruction() {
43 auto sp = shared_from_this();
44
45 g_signal_connect(device_iface_.get(), "handle-connect",
46 G_CALLBACK(&NetworkDeviceSkeleton::OnHandleConnect),
47 new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
48 g_signal_connect(device_iface_.get(), "handle-disconnect",
49 G_CALLBACK(&NetworkDeviceSkeleton::OnHandleDisconnect),
50 new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
51
52 SyncProperties();
53
54 if (!object_)
55 ERROR("Failed to create object for device %s", Address());
56 else
57 aethercast_interface_object_skeleton_set_device(object_.get(), device_iface_.get());
58
59 return sp;
60}
61
62void NetworkDeviceSkeleton::SyncProperties() {
63 aethercast_interface_device_set_address(device_iface_.get(), Address().c_str());
64 aethercast_interface_device_set_name(device_iface_.get(), Name().c_str());
65 aethercast_interface_device_set_state(device_iface_.get(), NetworkDevice::StateToStr(State()).c_str());
66
67 auto capabilities = DBusHelpers::GenerateDeviceCapabilities(SupportedRoles());
68 aethercast_interface_device_set_capabilities(device_iface_.get(), capabilities);
69 g_strfreev(capabilities);
70}
71
72GDBusObjectSkeleton* NetworkDeviceSkeleton::DBusObject() const {
73 return G_DBUS_OBJECT_SKELETON(object_.get());
74}
75
76std::string NetworkDeviceSkeleton::Path() const {
77 return path_;
78}
79
80// TODO(tvoss,morphis): Refactor mcs::NetworkDevice to have Connect/Disconnect defined on its interfaces.
81// It feels quite dirty to require both an instance of mcs::NetworkDevice and mcs::MiracastController to
82// implement the connect/disconnect calls coming in via the bus. The complication then is the async handling of
83// the invocation, as we will likely have to reach out to WPASupplicant for example (which is dispatched via the same
84// event loop as we are). In addition, we should not start littering our public interfaces by handing down callbacks.
85gboolean NetworkDeviceSkeleton::OnHandleConnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
86 const gchar *role, gpointer user_data)
87{
88 boost::ignore_unused_variable_warning(skeleton);
89 boost::ignore_unused_variable_warning(role);
90
91 auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
92
93 if (not inst) {
94 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
95 return TRUE;
96 }
97
98 g_object_ref(invocation);
99 auto inv = make_shared_gobject(invocation);
100
101 inst->controller_->Connect(inst->Fwd(), [inv](mcs::Error error) {
102 if (error != Error::kNone) {
103 g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
104 "%s", mcs::ErrorToString(error).c_str());
105 return;
106 }
107
108 g_dbus_method_invocation_return_value(inv.get(), nullptr);
109 });
110
111 return TRUE;
112}
113
114gboolean NetworkDeviceSkeleton::OnHandleDisconnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
115 gpointer user_data)
116{
117 boost::ignore_unused_variable_warning(skeleton);
118
119 auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
120
121 if (not inst) {
122 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
123 return TRUE;
124 }
125
126 g_object_ref(invocation);
127 auto inv = make_shared_gobject(invocation);
128
129 inst->controller_->Disconnect(inst->Fwd(), [inv](mcs::Error error) {
130 if (error != Error::kNone) {
131 g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
132 "%s", mcs::ErrorToString(error).c_str());
133 return;
134 }
135
136 g_dbus_method_invocation_return_value(inv.get(), nullptr);
137 });
138
139 return TRUE;
140}
141
142} // namespace mcs
1430
=== modified file 'src/mcs/networkutils.cpp'
--- src/mcs/networkutils.cpp 2016-01-15 19:31:22 +0000
+++ src/mcs/networkutils.cpp 2016-02-25 12:47:02 +0000
@@ -15,17 +15,28 @@
15 *15 *
16 */16 */
1717
18
18#include <sys/ioctl.h>19#include <sys/ioctl.h>
19#include <net/if.h>
20#include <asm/types.h>20#include <asm/types.h>
21#include <linux/netlink.h>
22#include <linux/rtnetlink.h>
23#include <sys/socket.h>21#include <sys/socket.h>
24#include <netinet/in.h>22#include <netinet/in.h>
25#include <arpa/inet.h>23#include <arpa/inet.h>
26#include <unistd.h>24#include <unistd.h>
27#include <errno.h>25#include <errno.h>
28#include <memory.h>26#include <memory.h>
27#include <stdlib.h>
28#include <errno.h>
29
30#include <linux/netlink.h>
31#include <linux/rtnetlink.h>
32
33// Hacks necessary to be able to include wireless.h
34#ifndef __user
35#define __user
36#endif
37
38#include <linux/if.h>
39#include <linux/wireless.h>
2940
30#include <glib.h>41#include <glib.h>
3142
@@ -33,6 +44,9 @@
33#include "networkutils.h"44#include "networkutils.h"
34#include "logger.h"45#include "logger.h"
3546
47namespace {
48static constexpr size_t kDriverCommandReplySize{1024};
49
36#define NLMSG_TAIL(nmsg) \50#define NLMSG_TAIL(nmsg) \
37 ((struct rtattr *) (((uint8_t*) (nmsg)) + \51 ((struct rtattr *) (((uint8_t*) (nmsg)) + \
38 NLMSG_ALIGN((nmsg)->nlmsg_len)))52 NLMSG_ALIGN((nmsg)->nlmsg_len)))
@@ -56,6 +70,7 @@
5670
57 return 0;71 return 0;
58}72}
73}
5974
60namespace mcs {75namespace mcs {
61int NetworkUtils::ModifyInterfaceAddress(int cmd, int flags,76int NetworkUtils::ModifyInterfaceAddress(int cmd, int flags,
@@ -259,4 +274,47 @@
259 available = (int64_t) nbytes;274 available = (int64_t) nbytes;
260 return available;275 return available;
261}276}
277
278typedef struct {
279#ifdef SUPPORT_64BIT
280 u64 bufaddr;
281#else
282 char *bufaddr;
283#endif
284 int used_len;
285 int total_len;
286} android_wifi_priv_cmd;
287
288int NetworkUtils::SendDriverPrivateCommand(const std::string &ifname, const std::string &cmd) {
289 struct ifreq ifr;
290 int ret = 0, s;
291 android_wifi_priv_cmd priv_cmd;
292 char buf[kDriverCommandReplySize];
293 size_t buf_len = kDriverCommandReplySize;
294
295 ::memset(buf, 0, sizeof(buf));
296 ::memcpy(buf, cmd.c_str(), cmd.length() + 1);
297 ::memset(&ifr, 0, sizeof(ifr));
298 ::memset(&priv_cmd, 0, sizeof(priv_cmd));
299
300 ::strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
301
302#ifdef SUPPORT_64BIT
303 priv_cmd.bufaddr = (u64)(uintptr_t) buf;
304#else
305 priv_cmd.bufaddr = buf;
306#endif
307 priv_cmd.used_len = buf_len;
308 priv_cmd.total_len = buf_len;
309 ifr.ifr_data = &priv_cmd;
310
311 s = ::socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
312 if (s < 0)
313 return -EIO;
314
315 ret = ::ioctl(s, SIOCDEVPRIVATE + 1, &ifr);
316 ::close(s);
317 return ret;
318}
319
262} // namespace mcs320} // namespace mcs
263321
=== modified file 'src/mcs/networkutils.h'
--- src/mcs/networkutils.h 2016-01-15 19:31:22 +0000
+++ src/mcs/networkutils.h 2016-02-25 12:47:02 +0000
@@ -18,6 +18,8 @@
18#ifndef NETWORKUTILS_H_18#ifndef NETWORKUTILS_H_
19#define NETWORKUTILS_H_19#define NETWORKUTILS_H_
2020
21#include <string>
22
21namespace mcs {23namespace mcs {
22class NetworkUtils24class NetworkUtils
23{25{
@@ -29,6 +31,7 @@
29 unsigned char prefixlen, const char *broadcast);31 unsigned char prefixlen, const char *broadcast);
30 static int ResetInterface(int index);32 static int ResetInterface(int index);
31 static int BytesAvailableToRead(int fd);33 static int BytesAvailableToRead(int fd);
34 static int SendDriverPrivateCommand(const std::string &ifname, const std::string &cmd);
32};35};
33} // namespace mcs36} // namespace mcs
34#endif37#endif
3538
=== added directory 'src/mcs/streaming'
=== added file 'src/mcs/streaming/mpegtspacketizer.cpp'
--- src/mcs/streaming/mpegtspacketizer.cpp 1970-01-01 00:00:00 +0000
+++ src/mcs/streaming/mpegtspacketizer.cpp 2016-02-25 12:47:02 +0000
@@ -0,0 +1,831 @@
1/*
2 * Copyright 2012, The Android Open Source Project
3 * Copyright (C) 2016 Canonical, Ltd.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/**
19 * NOTE: The implementation is based on the Android implementation for WiFi
20 * display support in frameworks/av/libstagefright/wifi-display/TSPacketizer.cpp
21 * and is adjusted for our needs.
22 */
23
24#include <arpa/inet.h>
25#include <memory.h>
26
27#include "mcs/utils.h"
28#include "mcs/logger.h"
29
30#include "mcs/video/utils.h"
31
32#include "mcs/streaming/mpegtspacketizer.h"
33
34namespace {
35const unsigned int kPIDofPMT = 0x100;
36const unsigned int kPIDofPCR = 0x1000;
37}
38
39namespace mcs {
40namespace streaming {
41
42struct MPEGTSPacketizer::Track {
43 typedef std::shared_ptr<Track> Ptr;
44
45 static Ptr Create(const TrackFormat &format, unsigned int pid,
46 unsigned int stream_type, unsigned int stream_id);
47
48 unsigned int PID() const { return pid_; }
49 unsigned int StreamType() const { return stream_type_; }
50 unsigned int StreamId() const { return stream_id_; }
51 TrackFormat Format() const { return format_; }
52
53 unsigned int NextContinuityCounter();
54
55 bool IsAudio() const { return mcs::Utils::StringStartsWith(format_.mime, "audio/"); }
56 bool IsVideo() const { return mcs::Utils::StringStartsWith(format_.mime, "video/"); }
57
58 bool IsH264() const { return format_.mime == "video/avc"; }
59
60 void SubmitCSD(const mcs::video::Buffer::Ptr &buffer);
61
62 mcs::video::Buffer::Ptr PrependCSD(const mcs::video::Buffer::Ptr &buffer) const;
63
64 void Finalize();
65
66 std::vector<mcs::video::Buffer::Ptr> Descriptors() const { return descriptors_; }
67
68private:
69 Track(const TrackFormat &format, unsigned int pid,
70 unsigned int stream_type, unsigned int stream_id);
71
72private:
73 TrackFormat format_;
74 unsigned int pid_;
75 unsigned int stream_type_;
76 unsigned int stream_id_;
77 unsigned int continuity_counter_;
78 bool finalized_;
79 std::vector<mcs::video::Buffer::Ptr> csd_;
80 std::vector<mcs::video::Buffer::Ptr> descriptors_;
81};
82
83MPEGTSPacketizer::Track::Ptr MPEGTSPacketizer::Track::Create(const TrackFormat &format, unsigned int pid,
84 unsigned int stream_type, unsigned int stream_id) {
85 return std::shared_ptr<Track>(new Track(format, pid, stream_type, stream_id));
86}
87
88MPEGTSPacketizer::Track::Track(const TrackFormat &format, unsigned int pid,
89 unsigned int stream_type, unsigned int stream_id) :
90 format_(format),
91 pid_(pid),
92 stream_type_(stream_type),
93 stream_id_(stream_id),
94 continuity_counter_(0),
95 finalized_(false) {
96}
97
98unsigned int MPEGTSPacketizer::Track::NextContinuityCounter() {
99 unsigned int prev = continuity_counter_;
100 if (++continuity_counter_ == 16)
101 continuity_counter_ = 0;
102 return prev;
103}
104
105void MPEGTSPacketizer::Track::SubmitCSD(const video::Buffer::Ptr &buffer) {
106 if (!IsH264())
107 return;
108
109 const uint8_t *data = buffer->Data();
110 size_t size = buffer->Length();
111
112 const uint8_t *nal_start;
113 size_t nal_size;
114
115 while (mcs::video::GetNextNALUnit(&data, &size, &nal_start, &nal_size, true)) {
116 auto csd = mcs::video::Buffer::Create(nal_size + 4);
117
118 ::memcpy(csd->Data(), "\x00\x00\x00\x01", 4);
119 ::memcpy(csd->Data() + 4, nal_start, nal_size);
120
121 csd_.push_back(csd);
122 }
123}
124
125mcs::video::Buffer::Ptr MPEGTSPacketizer::Track::PrependCSD(const mcs::video::Buffer::Ptr &buffer) const {
126 size_t size = 0;
127 for (auto csd : csd_)
128 size += csd->Length();
129
130 auto new_buffer = mcs::video::Buffer::Create(buffer->Length() + size);
131 size_t offset = 0;
132 for (auto csd : csd_) {
133 ::memcpy(new_buffer->Data() + offset, csd->Data(), csd->Length());
134 offset += csd->Length();
135 }
136
137 ::memcpy(new_buffer->Data() + offset, buffer->Data(), buffer->Length());
138
139 return new_buffer;
140}
141
142void MPEGTSPacketizer::Track::Finalize() {
143 if (finalized_)
144 return;
145
146 if(!IsH264())
147 return;
148
149 MCS_DEBUG("");
150
151 {
152 // AVC video descriptor (40)
153 auto descriptor = mcs::video::Buffer::Create(6);
154 uint8_t *data = descriptor->Data();
155 data[0] = 40; // descriptor_tag
156 data[1] = 4; // descriptor_length
157
158 if (csd_.size() > 0) {
159 // Seems to be a conventation that the first NAL we get
160 // submitted as part of the codec-specific data is the
161 // SPS we want here.
162 auto sps = csd_.at(0);
163 // We skip the first four bytes (NAL preamble) and then
164 // just copy profile/constraint/level settings
165 memcpy(&data[2], sps->Data() + 4, 3);
166 }
167 else {
168 data[2] = format_.profile_idc; // profile_idc
169 data[3] = format_.constraint_set; // constraint_set*
170 data[4] = format_.level_idc; // level_idc
171 }
172
173 // AVC_still_present=0, AVC_24_hour_picture_flag=0, reserved
174 data[5] = 0x3f;
175
176 descriptors_.push_back(descriptor);
177 }
178 {
179 // AVC timing and HRD descriptor (42)
180
181 auto descriptor = mcs::video::Buffer::Create(4);
182 uint8_t *data = descriptor->Data();
183 data[0] = 42; // descriptor_tag
184 data[1] = 2; // descriptor_length
185
186 // hrd_management_valid_flag = 0
187 // reserved = 111111b
188 // picture_and_timing_info_present = 0
189
190 data[2] = 0x7e;
191
192 // fixed_frame_rate_flag = 0
193 // temporal_poc_flag = 0
194 // picture_to_display_conversion_flag = 0
195 // reserved = 11111b
196 data[3] = 0x1f;
197
198 descriptors_.push_back(descriptor);
199 }
200
201 finalized_ = true;
202}
203
204MPEGTSPacketizer::Ptr MPEGTSPacketizer::Create() {
205 return std::shared_ptr<MPEGTSPacketizer>(new MPEGTSPacketizer);
206}
207
208MPEGTSPacketizer::MPEGTSPacketizer() :
209 pat_continuity_counter_(0),
210 pmt_continuity_counter_(0) {
211 InitCrcTable();
212}
213
214MPEGTSPacketizer::~MPEGTSPacketizer() {
215}
216
217MPEGTSPacketizer::TrackId MPEGTSPacketizer::AddTrack(const TrackFormat &format) {
218 auto is_video = mcs::Utils::StringStartsWith(format.mime, "video/");
219
220 if (!is_video) {
221 MCS_ERROR("Audio tracks for MPEGTS are currently not supported");
222 return TrackId(-1);
223 }
224
225 if (format.mime != "video/avc") {
226 MCS_ERROR("Video formats other than video/avc are not supported");
227 return TrackId(-1);
228 }
229
230 // First PID as per WiFi Display spec
231 unsigned int pid_start = 0x1011;
232 unsigned int stream_type = 0x1b;
233 unsigned int stream_id_start = 0xe0;
234 unsigned int stream_id_stop = 0xef;
235
236 unsigned int num_same_tracks = 0;
237 unsigned int pid = pid_start;
238
239 for (auto track : tracks_) {
240 if (track->StreamType() == stream_type)
241 num_same_tracks++;
242
243 if (track->IsAudio() || track->IsVideo())
244 pid++;
245 }
246
247 unsigned int stream_id = stream_id_start + num_same_tracks;
248 if (stream_id > stream_id_stop) {
249 MCS_ERROR("All stream ids are in use");
250 return TrackId(-1);
251 }
252
253 auto track = Track::Create(format, pid, stream_type, stream_id);
254 tracks_.push_back(track);
255
256 return tracks_.size() - 1;
257}
258
259void MPEGTSPacketizer::SubmitCSD(TrackId track_index, const video::Buffer::Ptr &buffer) {
260 if (track_index > tracks_.size() -1)
261 return;
262
263 auto track = tracks_.at(track_index);
264 track->SubmitCSD(buffer);
265}
266
267bool MPEGTSPacketizer::Packetize(TrackId track_index, const video::Buffer::Ptr &_access_unit,
268 video::Buffer::Ptr *packets, int flags) {
269 size_t numStuffingBytes = 0;
270 const uint8_t *PES_private_data = nullptr;
271 size_t PES_private_data_len = 0;
272 mcs::video::Buffer::Ptr access_unit = _access_unit;
273 int64_t timeUs = access_unit->Timestamp();
274
275 packets->reset();
276
277 if (track_index > tracks_.size() - 1) {
278 MCS_ERROR("Invalid track index %d supplied", track_index);
279 return false;
280 }
281
282 auto track = tracks_.at(track_index);
283
284 if (track->IsH264() && (flags & Flags::kPrependSPSandPPStoIDRFrames)
285 && mcs::video::DoesBufferContainIDRFrame(access_unit)) {
286 // prepend codec specific data, i.e. SPS and PPS.
287 access_unit = track->PrependCSD(access_unit);
288 }
289
290 // 0x47
291 // transport_error_indicator = b0
292 // payload_unit_start_indicator = b1
293 // transport_priority = b0
294 // PID
295 // transport_scrambling_control = b00
296 // adaptation_field_control = b??
297 // continuity_counter = b????
298 // -- payload follows
299 // packet_startcode_prefix = 0x000001
300 // stream_id
301 // PES_packet_length = 0x????
302 // reserved = b10
303 // PES_scrambling_control = b00
304 // PES_priority = b0
305 // data_alignment_indicator = b1
306 // copyright = b0
307 // original_or_copy = b0
308 // PTS_DTS_flags = b10 (PTS only)
309 // ESCR_flag = b0
310 // ES_rate_flag = b0
311 // DSM_trick_mode_flag = b0
312 // additional_copy_info_flag = b0
313 // PES_CRC_flag = b0
314 // PES_extension_flag = b0
315 // PES_header_data_length = 0x05
316 // reserved = b0010 (PTS)
317 // PTS[32..30] = b???
318 // reserved = b1
319 // PTS[29..15] = b??? ???? ???? ???? (15 bits)
320 // reserved = b1
321 // PTS[14..0] = b??? ???? ???? ???? (15 bits)
322 // reserved = b1
323 // the first fragment of "buffer" follows
324
325 // Each transport packet (except for the last one contributing to the PES
326 // payload) must contain a multiple of 16 bytes of payload per HDCP spec.
327 bool alignPayload = false;
328
329 /*
330 a) The very first PES transport stream packet contains
331
332 4 bytes of TS header
333 ... padding
334 14 bytes of static PES header
335 PES_private_data_len + 1 bytes (only if PES_private_data_len > 0)
336 numStuffingBytes bytes
337
338 followed by the payload
339
340 b) Subsequent PES transport stream packets contain
341
342 4 bytes of TS header
343 ... padding
344
345 followed by the payload
346 */
347
348 size_t PES_packet_length = access_unit->Length() + 8 + numStuffingBytes;
349 if (PES_private_data_len > 0)
350 PES_packet_length += PES_private_data_len + 1;
351
352 size_t numTSPackets = 1;
353
354 {
355 // Make sure the PES header fits into a single TS packet:
356 size_t PES_header_size = 14 + numStuffingBytes;
357 if (PES_private_data_len > 0) {
358 PES_header_size += PES_private_data_len + 1;
359 }
360
361 if (PES_header_size > 188u - 4u)
362 MCS_FATAL("Invalid header size");
363
364 size_t sizeAvailableForPayload = 188 - 4 - PES_header_size;
365 size_t numBytesOfPayload = access_unit->Length();
366
367 if (numBytesOfPayload > sizeAvailableForPayload) {
368 numBytesOfPayload = sizeAvailableForPayload;
369
370 if (alignPayload && numBytesOfPayload > 16) {
371 numBytesOfPayload -= (numBytesOfPayload % 16);
372 }
373 }
374
375 size_t numBytesOfPayloadRemaining = access_unit->Length() - numBytesOfPayload;
376
377 // This is how many bytes of payload each subsequent TS packet
378 // can contain at most.
379 sizeAvailableForPayload = 188 - 4;
380 size_t sizeAvailableForAlignedPayload = sizeAvailableForPayload;
381 if (alignPayload) {
382 // We're only going to use a subset of the available space
383 // since we need to make each fragment a multiple of 16 in size.
384 sizeAvailableForAlignedPayload -=
385 (sizeAvailableForAlignedPayload % 16);
386 }
387
388 size_t numFullTSPackets =
389 numBytesOfPayloadRemaining / sizeAvailableForAlignedPayload;
390
391 numTSPackets += numFullTSPackets;
392
393 numBytesOfPayloadRemaining -=
394 numFullTSPackets * sizeAvailableForAlignedPayload;
395
396 // numBytesOfPayloadRemaining < sizeAvailableForAlignedPayload
397 if (numFullTSPackets == 0 && numBytesOfPayloadRemaining > 0) {
398 // There wasn't enough payload left to form a full aligned payload,
399 // the last packet doesn't have to be aligned.
400 ++numTSPackets;
401 } else if (numFullTSPackets > 0
402 && numBytesOfPayloadRemaining
403 + sizeAvailableForAlignedPayload > sizeAvailableForPayload) {
404 // The last packet emitted had a full aligned payload and together
405 // with the bytes remaining does exceed the unaligned payload
406 // size, so we need another packet.
407 ++numTSPackets;
408 }
409 }
410
411 if (flags & Flags::kEmitPATandPMT)
412 numTSPackets += 2;
413
414 if (flags & Flags::kEmitPCR)
415 ++numTSPackets;
416
417 auto buffer = mcs::video::Buffer::Create(numTSPackets * 188);
418 buffer->SetTimestamp(access_unit->Timestamp());
419
420 uint8_t *packetDataStart = buffer->Data();
421
422 if (flags & Flags::kEmitPATandPMT) {
423 // Program Association Table (PAT):
424 // 0x47
425 // transport_error_indicator = b0
426 // payload_unit_start_indicator = b1
427 // transport_priority = b0
428 // PID = b0000000000000 (13 bits)
429 // transport_scrambling_control = b00
430 // adaptation_field_control = b01 (no adaptation field, payload only)
431 // continuity_counter = b????
432 // skip = 0x00
433 // --- payload follows
434 // table_id = 0x00
435 // section_syntax_indicator = b1
436 // must_be_zero = b0
437 // reserved = b11
438 // section_length = 0x00d
439 // transport_stream_id = 0x0000
440 // reserved = b11
441 // version_number = b00001
442 // current_next_indicator = b1
443 // section_number = 0x00
444 // last_section_number = 0x00
445 // one program follows:
446 // program_number = 0x0001
447 // reserved = b111
448 // program_map_PID = kPID_PMT (13 bits!)
449 // CRC = 0x????????
450
451 if (++pat_continuity_counter_ == 16)
452 pat_continuity_counter_ = 0;
453
454 uint8_t *ptr = packetDataStart;
455 *ptr++ = 0x47;
456 *ptr++ = 0x40;
457 *ptr++ = 0x00;
458 *ptr++ = 0x10 | pat_continuity_counter_;
459 *ptr++ = 0x00;
460
461 uint8_t *crcDataStart = ptr;
462 *ptr++ = 0x00;
463 *ptr++ = 0xb0;
464 *ptr++ = 0x0d;
465 *ptr++ = 0x00;
466 *ptr++ = 0x00;
467 *ptr++ = 0xc3;
468 *ptr++ = 0x00;
469 *ptr++ = 0x00;
470 *ptr++ = 0x00;
471 *ptr++ = 0x01;
472 *ptr++ = 0xe0 | (kPIDofPMT >> 8);
473 *ptr++ = kPIDofPMT & 0xff;
474
475 if (ptr - crcDataStart != 12)
476 MCS_FATAL("Invalid position for ptr");
477
478 uint32_t crc = ::htonl(CalcCrc32(crcDataStart, ptr - crcDataStart));
479 ::memcpy(ptr, &crc, 4);
480 ptr += 4;
481
482 size_t sizeLeft = packetDataStart + 188 - ptr;
483 ::memset(ptr, 0xff, sizeLeft);
484
485 packetDataStart += 188;
486
487 // Program Map (PMT):
488 // 0x47
489 // transport_error_indicator = b0
490 // payload_unit_start_indicator = b1
491 // transport_priority = b0
492 // PID = kPID_PMT (13 bits)
493 // transport_scrambling_control = b00
494 // adaptation_field_control = b01 (no adaptation field, payload only)
495 // continuity_counter = b????
496 // skip = 0x00
497 // -- payload follows
498 // table_id = 0x02
499 // section_syntax_indicator = b1
500 // must_be_zero = b0
501 // reserved = b11
502 // section_length = 0x???
503 // program_number = 0x0001
504 // reserved = b11
505 // version_number = b00001
506 // current_next_indicator = b1
507 // section_number = 0x00
508 // last_section_number = 0x00
509 // reserved = b111
510 // PCR_PID = kPCR_PID (13 bits)
511 // reserved = b1111
512 // program_info_length = 0x???
513 // program_info_descriptors follow
514 // one or more elementary stream descriptions follow:
515 // stream_type = 0x??
516 // reserved = b111
517 // elementary_PID = b? ???? ???? ???? (13 bits)
518 // reserved = b1111
519 // ES_info_length = 0x000
520 // CRC = 0x????????
521
522 if (++pmt_continuity_counter_ == 16)
523 pmt_continuity_counter_ = 0;
524
525 ptr = packetDataStart;
526
527 *ptr++ = 0x47;
528 *ptr++ = 0x40 | (kPIDofPMT >> 8);
529 *ptr++ = kPIDofPMT & 0xff;
530 *ptr++ = 0x10 | pmt_continuity_counter_;
531 *ptr++ = 0x00;
532
533 crcDataStart = ptr;
534 *ptr++ = 0x02;
535
536 *ptr++ = 0x00; // section_length to be filled in below.
537 *ptr++ = 0x00;
538
539 *ptr++ = 0x00;
540 *ptr++ = 0x01;
541 *ptr++ = 0xc3;
542 *ptr++ = 0x00;
543 *ptr++ = 0x00;
544 *ptr++ = 0xe0 | (kPIDofPCR >> 8);
545 *ptr++ = kPIDofPCR & 0xff;
546
547 size_t program_info_length = 0;
548 for (auto descriptor : program_info_descriptors_)
549 program_info_length += descriptor->Length();
550
551 if(program_info_length >= 0x400)
552 MCS_FATAL("Invalid length for program info");
553
554 *ptr++ = 0xf0 | (program_info_length >> 8);
555 *ptr++ = (program_info_length & 0xff);
556
557 for (auto descriptor : program_info_descriptors_) {
558 ::memcpy(ptr, descriptor->Data(), descriptor->Length());
559 ptr += descriptor->Length();
560 }
561
562 for (auto track : tracks_) {
563 // Make sure all the decriptors have been added.
564 track->Finalize();
565
566 *ptr++ = track->StreamType();
567 *ptr++ = 0xe0 | (track->PID() >> 8);
568 *ptr++ = track->PID() & 0xff;
569
570 auto descriptors = track->Descriptors();
571
572 size_t ES_info_length = 0;
573 for (auto descriptor : descriptors)
574 ES_info_length += descriptor->Length();
575
576 if (ES_info_length > 0xfff)
577 MCS_FATAL("Invalid ES length %d", ES_info_length);
578
579 *ptr++ = 0xf0 | (ES_info_length >> 8);
580 *ptr++ = (ES_info_length & 0xff);
581
582 for (auto descriptor : descriptors) {
583 memcpy(ptr, descriptor->Data(), descriptor->Length());
584 ptr += descriptor->Length();
585 }
586 }
587
588 size_t section_length = ptr - (crcDataStart + 3) + 4 /* CRC */;
589
590 crcDataStart[1] = 0xb0 | (section_length >> 8);
591 crcDataStart[2] = section_length & 0xff;
592
593 crc = ::htonl(CalcCrc32(crcDataStart, ptr - crcDataStart));
594 memcpy(ptr, &crc, 4);
595 ptr += 4;
596
597 sizeLeft = packetDataStart + 188 - ptr;
598 memset(ptr, 0xff, sizeLeft);
599
600 packetDataStart += 188;
601 }
602
603 if (flags & Flags::kEmitPCR) {
604 // PCR stream
605 // 0x47
606 // transport_error_indicator = b0
607 // payload_unit_start_indicator = b1
608 // transport_priority = b0
609 // PID = kPCR_PID (13 bits)
610 // transport_scrambling_control = b00
611 // adaptation_field_control = b10 (adaptation field only, no payload)
612 // continuity_counter = b0000 (does not increment)
613 // adaptation_field_length = 183
614 // discontinuity_indicator = b0
615 // random_access_indicator = b0
616 // elementary_stream_priority_indicator = b0
617 // PCR_flag = b1
618 // OPCR_flag = b0
619 // splicing_point_flag = b0
620 // transport_private_data_flag = b0
621 // adaptation_field_extension_flag = b0
622 // program_clock_reference_base = b?????????????????????????????????
623 // reserved = b111111
624 // program_clock_reference_extension = b?????????
625
626 int64_t nowUs = mcs::Utils::GetNowUs();
627 uint64_t PCR = nowUs * 27; // PCR based on a 27MHz clock
628 uint64_t PCR_base = PCR / 300;
629 uint32_t PCR_ext = PCR % 300;
630
631 uint8_t *ptr = packetDataStart;
632 *ptr++ = 0x47;
633 *ptr++ = 0x40 | (kPIDofPCR >> 8);
634 *ptr++ = kPIDofPCR & 0xff;
635 *ptr++ = 0x20;
636 *ptr++ = 0xb7; // adaptation_field_length
637 *ptr++ = 0x10;
638 *ptr++ = (PCR_base >> 25) & 0xff;
639 *ptr++ = (PCR_base >> 17) & 0xff;
640 *ptr++ = (PCR_base >> 9) & 0xff;
641 *ptr++ = ((PCR_base & 1) << 7) | 0x7e | ((PCR_ext >> 8) & 1);
642 *ptr++ = (PCR_ext & 0xff);
643
644 size_t sizeLeft = packetDataStart + 188 - ptr;
645 ::memset(ptr, 0xff, sizeLeft);
646
647 packetDataStart += 188;
648 }
649
650 // Adjust time to 90kHz
651 uint64_t PTS = (timeUs * 9ll) / 100ll;
652
653 if (PES_packet_length >= 65536) {
654 // This really should only happen for video.
655 if (!track->IsVideo())
656 MCS_FATAL("PES packet length too hight; should only happen for video (track %d mime %s)",
657 track_index, track->Format().mime);
658
659 MCS_WARNING("Reset PES packet length to 0");
660
661 // It's valid to set this to 0 for video according to the specs.
662 PES_packet_length = 0;
663 }
664
665 size_t sizeAvailableForPayload = 188 - 4 - 14 - numStuffingBytes;
666 if (PES_private_data_len > 0) {
667 sizeAvailableForPayload -= PES_private_data_len + 1;
668 }
669
670 size_t copy = access_unit->Length();
671
672 if (copy > sizeAvailableForPayload) {
673 copy = sizeAvailableForPayload;
674
675 if (alignPayload && copy > 16) {
676 copy -= (copy % 16);
677 }
678 }
679
680 size_t numPaddingBytes = sizeAvailableForPayload - copy;
681
682 uint8_t *ptr = packetDataStart;
683 *ptr++ = 0x47;
684 *ptr++ = 0x40 | (track->PID() >> 8);
685 *ptr++ = track->PID() & 0xff;
686
687 *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
688 | track->NextContinuityCounter();
689
690 if (numPaddingBytes > 0) {
691 *ptr++ = numPaddingBytes - 1;
692 if (numPaddingBytes >= 2) {
693 *ptr++ = 0x00;
694 ::memset(ptr, 0xff, numPaddingBytes - 2);
695 ptr += numPaddingBytes - 2;
696 }
697 }
698
699 *ptr++ = 0x00;
700 *ptr++ = 0x00;
701 *ptr++ = 0x01;
702 *ptr++ = track->StreamId();
703 *ptr++ = PES_packet_length >> 8;
704 *ptr++ = PES_packet_length & 0xff;
705 *ptr++ = 0x84;
706 *ptr++ = (PES_private_data_len > 0) ? 0x81 : 0x80;
707
708 size_t headerLength = 0x05 + numStuffingBytes;
709 if (PES_private_data_len > 0) {
710 headerLength += 1 + PES_private_data_len;
711 }
712
713 *ptr++ = headerLength;
714
715 *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
716 *ptr++ = (PTS >> 22) & 0xff;
717 *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1;
718 *ptr++ = (PTS >> 7) & 0xff;
719 *ptr++ = ((PTS & 0x7f) << 1) | 1;
720
721 if (PES_private_data_len > 0) {
722 *ptr++ = 0x8e; // PES_private_data_flag, reserved.
723 ::memcpy(ptr, PES_private_data, PES_private_data_len);
724 ptr += PES_private_data_len;
725 }
726
727 for (size_t i = 0; i < numStuffingBytes; ++i) {
728 *ptr++ = 0xff;
729 }
730
731 ::memcpy(ptr, access_unit->Data(), copy);
732 ptr += copy;
733
734 if (ptr != packetDataStart + 188)
735 MCS_FATAL("Invalid pointer %p", ptr);
736
737 packetDataStart += 188;
738
739 size_t offset = copy;
740 while (offset < access_unit->Length()) {
741 // for subsequent fragments of "buffer":
742 // 0x47
743 // transport_error_indicator = b0
744 // payload_unit_start_indicator = b0
745 // transport_priority = b0
746 // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
747 // transport_scrambling_control = b00
748 // adaptation_field_control = b??
749 // continuity_counter = b????
750 // the fragment of "buffer" follows.
751
752 size_t sizeAvailableForPayload = 188 - 4;
753
754 size_t copy = access_unit->Length() - offset;
755
756 if (copy > sizeAvailableForPayload) {
757 copy = sizeAvailableForPayload;
758
759 if (alignPayload && copy > 16) {
760 copy -= (copy % 16);
761 }
762 }
763
764 size_t numPaddingBytes = sizeAvailableForPayload - copy;
765
766 uint8_t *ptr = packetDataStart;
767 *ptr++ = 0x47;
768 *ptr++ = 0x00 | (track->PID() >> 8);
769 *ptr++ = track->PID() & 0xff;
770
771 *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
772 | track->NextContinuityCounter();
773
774 if (numPaddingBytes > 0) {
775 *ptr++ = numPaddingBytes - 1;
776 if (numPaddingBytes >= 2) {
777 *ptr++ = 0x00;
778 memset(ptr, 0xff, numPaddingBytes - 2);
779 ptr += numPaddingBytes - 2;
780 }
781 }
782
783 memcpy(ptr, access_unit->Data() + offset, copy);
784 ptr += copy;
785 if (ptr != packetDataStart + 188)
786 MCS_FATAL("Invalid pointer position %p", ptr);
787
788 offset += copy;
789 packetDataStart += 188;
790 }
791
792 if (packetDataStart != buffer->Data() + buffer->Length())
793 MCS_FATAL("Invalid packet start position");
794
795 *packets = buffer;
796
797#if 0
798 auto now = mcs::Utils::GetNowUs();
799 MCS_DEBUG("Buffer packtized after %lld ms (timestamp %lld now %lld)",
800 (now - buffer->Timestamp()) / 1000ll,
801 buffer->Timestamp(), now);
802#endif
803
804 return true;
805}
806
807void MPEGTSPacketizer::InitCrcTable() {
808 uint32_t poly = 0x04C11DB7;
809
810 for (int i = 0; i < 256; i++) {
811 uint32_t crc = i << 24;
812 for (int j = 0; j < 8; j++) {
813 crc = (crc << 1) ^ ((crc & 0x80000000) ? (poly) : 0);
814 }
815 crc_table_[i] = crc;
816 }
817}
818
819uint32_t MPEGTSPacketizer::CalcCrc32(const uint8_t *start, size_t size) const {
820 uint32_t crc = 0xFFFFFFFF;
821 const uint8_t *p;
822
823 for (p = start; p < start + size; ++p) {
824 crc = (crc << 8) ^ crc_table_[((crc >> 24) ^ *p) & 0xFF];
825 }
826
827 return crc;
828}
829
830} // namespace streaming
831} // namespace mcs
0832
=== added file 'src/mcs/streaming/mpegtspacketizer.h'
--- src/mcs/streaming/mpegtspacketizer.h 1970-01-01 00:00:00 +0000
+++ src/mcs/streaming/mpegtspacketizer.h 2016-02-25 12:47:02 +0000
@@ -0,0 +1,97 @@
1/*
2 * Copyright 2012, The Android Open Source Project
3 * Copyright (C) 2016 Canonical, Ltd.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef MCS_STREAMING_MPEGTSPACKETIZER_H_
19#define MCS_STREAMING_MPEGTSPACKETIZER_H_
20
21#include <memory>
22#include <vector>
23
24#include <mcs/video/buffer.h>
25
26namespace mcs {
27namespace streaming {
28
29class MPEGTSPacketizer {
30public:
31 typedef std::shared_ptr<MPEGTSPacketizer> Ptr;
32 typedef int TrackId;
33
34 enum Flags {
35 kEmitPATandPMT = 1,
36 kEmitPCR = 2,
37 kIsEncrypted = 4,
38 kPrependSPSandPPStoIDRFrames = 8,
39 };
40
41 struct TrackFormat {
42 public:
43 TrackFormat(const std::string &mime = "",
44 unsigned int profile_idc = 0,
45 unsigned int level_idc = 0,
46 unsigned int constraint_set = 0) :
47 mime(mime),
48 profile_idc(profile_idc),
49 level_idc(level_idc),
50 constraint_set(constraint_set) {
51 }
52 TrackFormat(const TrackFormat &other) :
53 mime(other.mime),
54 profile_idc(other.profile_idc),
55 level_idc(other.level_idc),
56 constraint_set(other.constraint_set) {
57 }
58
59 std::string mime;
60 unsigned int profile_idc;
61 unsigned int level_idc;
62 unsigned int constraint_set;
63 };
64
65 static Ptr Create();
66
67 ~MPEGTSPacketizer();
68
69 TrackId AddTrack(const TrackFormat &format);
70
71 void SubmitCSD(TrackId track_index, const video::Buffer::Ptr &buffer);
72
73 bool Packetize(TrackId track_index, const video::Buffer::Ptr &access_unit,
74 video::Buffer::Ptr *packets, int flags = 0);
75
76private:
77 MPEGTSPacketizer();
78
79private:
80 void InitCrcTable();
81 uint32_t CalcCrc32(const uint8_t *start, size_t size) const;
82
83private:
84 struct Track;
85
86private:
87 unsigned int pat_continuity_counter_;
88 unsigned int pmt_continuity_counter_;
89 uint32_t crc_table_[256];
90 std::vector<std::shared_ptr<Track>> tracks_;
91 std::vector<video::Buffer::Ptr> program_info_descriptors_;
92};
93
94} // namespace streaming
95} // namespace mcs
96
97#endif
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: