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