求live中国植物图像数据库库下载

软件搜索:
软件分类导航
◎ &&>>&&>>&&>>&&>>&软件信息
Live&Interior&3D&Pro&功能强大的3D室内设计工具&支持10.82.8
◎ 软件介绍SOFT INTRODUCE
原价:129.95美元,约848元人民币
&&& Live Interior 3D Pro Edition是一款功能强大界面直观的3D室内设计工具。可设计房屋的尺寸,支持多房间单独设计。
&&& 如果你想更换房屋墙壁的颜色,安置一个全新的书柜又或者改变下家具的布置,那么在做所有的决定之前,不妨预先设计预览下布置后的成果。这时Live Interior 3D Pro Edition就能派上用场。
&&& Live Interior 3D Pro Edition的媒体数据库内置1000多套家具!与与Google 3D Warehouse相连接的Live Interior 3D Pro Edition能将各方面功能达到最优最人性化。
&&& 无法决定家具的设计和摆放位置,那么不妨试试Live Interior 3D Pro Editio内置的50套家具模板,尝试用不同的材料和家具装修房屋,可以让自己的家看起来更加舒适温馨。
&&& 此外,可在3D环境视角下导出整个内部环境(公寓或多媒体楼),修改家具参数,改变材质,直接使用Google SchetchUP编辑模型(Google3D Warehouse里可以搜到很多家具模型),也可设定虚拟摄像机轨道,生成QuickTime视频,随时渲染效果生成图片。
完全支持MacBook Pro视网膜用户界面完全增强添加高分辨率的实时3D渲染为视网膜显示屏(程序偏好& 3D设置)增强两向量2D和2D渲染模式增添全新的打印布局对话框印刷改进iBooks兼容导入和导出改进和Bug修复添加能够使用平移和缩放工具.重新设计的2D渲染改写所有2D
系统要求MAC OS X 10.5.8或者更高(支持10.8及以上系统)
◎ 软件下载SOFT DOWNLOAD
◎ 相关软件SOFT Recommend
暂未有相关软件!
◎ 软件评论SOFT COMMENT
评论时请自觉遵守互联网相关政策法规,不要恶意评论、广告和违禁词语。
◎ 下载必读DOWNLOAD EXPLANATION
注意:为达到最快速度,推荐使用迅雷、网际快车[Flashget]下载本站软件!
本站软件压缩包如需解压密码,请使用:,下载过程中有问题请联系网站客服。
站内提供的所有软件均是由网上搜集,任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担!任何从本站下载的破解文件、破解补丁、注册机、注册码、注册文件等一切形式的“特别信息”仅能作为学习研究目的使用,请您于24小时内自觉将其删除并向软件著者购买使用许可证。LiveBookstore 在线图书网站,数据库需要自己创建。图片信息 添加 Jsp/Servlet 238万源代码下载-
&文件名称: LiveBookstore& & [
& & & & &&]
&&所属分类:
&&开发工具: Java
&&文件大小: 2818 KB
&&上传时间:
&&下载次数: 0
&&提 供 者:
&详细说明:在线图书网站,数据库需要自己创建。图片信息自己添加-online
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&LiveBookstore&&.............\.classpath&&.............\.myeclipse&&.............\.mymetadata&&.............\.project&&.............\.settings&&.............\.........\.jsdtscope&&.............\.........\com.genuitec.eclipse.core.prefs&&.............\.........\org.eclipse.core.resources.prefs&&.............\.........\org.eclipse.jdt.core.prefs&&.............\.........\org.eclipse.wst.jsdt.ui.superType.container&&.............\.........\org.eclipse.wst.jsdt.ui.superType.name&&.............\src&&.............\...\cn&&.............\...\..\itcast&&.............\...\..\......\controller&&.............\...\..\......\..........\ClientServlet.java&&.............\...\..\......\..........\ManageServlet.java&&.............\...\..\......\..........\showPictrueServlet.java&&.............\...\..\......\dao&&.............\...\..\......\...\BookDao.java&&.............\...\..\......\...\CategoryDao.java&&.............\...\..\......\...\impl&&.............\...\..\......\...\....\BookDaoImpl.java&&.............\...\..\......\...\....\CategoryDaoImpl.java&&.............\...\..\......\...\....\OrdersDaoImpl.java&&.............\...\..\......\...\....\UserDaoImpl.java&&.............\...\..\......\...\OrdersDao.java&&.............\...\..\......\...\UserDao.java&&.............\...\..\......\domain&&.............\...\..\......\......\Book.java&&.............\...\..\......\......\Cart.java&&.............\...\..\......\......\CartItem.java&&.............\...\..\......\......\Category.java&&.............\...\..\......\......\Orders.java&&.............\...\..\......\......\OrdersItem.java&&.............\...\..\......\......\Page.java&&.............\...\..\......\......\User.java&&.............\...\..\......\exception&&.............\...\..\......\.........\UserExistException.java&&.............\...\..\......\service&&.............\...\..\......\.......\BusinessService.java&&.............\...\..\......\.......\impl&&.............\...\..\......\.......\....\BusinessServiceImpl.java&&.............\...\..\......\test&&.............\...\..\......\....\CategoryDaoImplTest.java&&.............\...\..\......\....\TestDBCP.java&&.............\...\..\......\utils&&.............\...\..\......\.....\DBCPUtil.java&&.............\...\..\......\.....\IdGender.java&&.............\...\..\......\.....\WebUtil.java&&.............\...\..\......\web&&.............\...\..\......\...\filter&&.............\...\..\......\...\......\AllCharacterEncodingFilter.java&&.............\...\..\......\...\functions&&.............\...\..\......\...\.........\FindCategoryById.java&&.............\...\dbcpconfig.properties&&.............\...\TestDBCP.java&&.............\WebRoot&&.............\.......\client&&.............\.......\......\header.jsp&&.............\.......\......\listOrders.jsp&&.............\.......\......\login.jsp&&.............\.......\......\message.jsp&&.............\.......\......\register.jsp&&.............\.......\......\showCart.jsp&&.............\.......\......\showCategoryBook.jsp&&.............\.......\......\showOrdersDetail.jsp&&.............\.......\......\welcome.jsp&&.............\.......\common&&.............\.......\......\message.jsp&&.............\.......\......\page.jsp&&.............\.......\css&&.............\.......\...\css.css&&.............\.......\files&&.............\.......\images&&.............\.......\......\menu_bg.gif&&.............\.......\......\menu_left.gif&&.............\.......\......\menu_line.gif&&.............\.......\......\menu_line2.gif&&.............\.......\......\menu_on_left.gif&&.............\.......\......\menu_on_left2.gif&&.............\.......\......\menu_on_right.gif&&.............\.......\......\menu_on_right2.gif&&.............\.......\......\menu_right.gif&&.............\.......\......\Thumbs.db&&.............\.......\index.jsp&&.............\.......\manager&&.............\.......\.......\addBook.jsp&&.............\.......\.......\addCategory.jsp&&.............\.......\.......\header.jsp&&.............\.......\.......\listAllCategory.jsp&&.............\.......\.......\showAllBook.jsp&&.............\.......\.......\showAllCatetoryUI.jsp&&.............\.......\.......\showOrders.jsp&&.............\.......\.......\showOrdersDetail.jsp&&.............\.......\.......\welcome.jsp&&.............\.......\message.jsp&&.............\.......\META-INF&&.............\.......\........\MANIFEST.MF
&输入关键字,在本站238万海量源码库中尽情搜索:时间相机(Timestamp C
&p&软件介绍&/p&
&p&时间相机是最好的能够在录像时能添加时间并精确到秒的手机软件。&/p&
&p&● 在拍照或者录像时添加当前时间和位置。您可以很容易地更改时间格式,或选择周围的地点。您还可以任意地设置时间地格式,在视频上的位置,改变字体,字体颜色及大小。&/p&
&p&● 在录像时可以暂停和继续录制。例如,您可以录制5秒,锁定您的设备,然后再返回到继续录5秒。那么你就可以得到一个包含所有10秒内容的视频。&/p&
&p&● 独特的梦幻粒子特效。20种不同的粒子特效,包括&星&,&雪&,&光&,&枫叶&,&心& ,&蝴蝶&,&花&,&三叶草&等。 ● 有一个有趣的舞蹈模式。看起来像相机在跳舞。这是世界上独一无二的功能。&/p&
&p&● 有4模式。 &视频& , &方形& , &跳舞&模式支持录制视频和拍摄照片。 &照片&模式经过了特殊的优化,在仅拍摄照片时有更好的效果。&/p&
&p&● 所有的效果都可应用于录像与拍照。&/p&
&p&● 可以在录像时改变效果,甚至可以切换前后摄像头。&/p&
&p&● 您可以导入图片作为虚拟摄像头。&/p&
&p&● 支持横屏和竖屏拍摄&/p&
&p&● 支持iPhone和iPad 如果您有任何问题或建议,请发邮件到。谢谢。&/p&
需要 iOS 7.0 或更高版本。
Yubin Chen (C)
Yubin Chen
&p&软件介绍&/p&
&p&AnimAuto App allows you to record videos of whatever you draw on your device screen instantly in real time. With its simple & easy to use interface, creating a nice & cool video will be effortless for everyone.&/p&
&p&AnimAuto App is the perfect tool to create self short video messages in animation or drawing forms!&/p&
&p&Main features include:&/p&
&p&& Set the brush color & adjust its thickness.&/p&
&p&& Change the background color of the drawing.&/p&
&p&& Use an image as the drawing background.&/p&
&p&& Pause & continue option between recordings to change brush color, thickness or background color.&/p&
&p&& Reset the frames to restart or start new recording.&/p&
&p&& Preview, rename or delete generated videos easily.&/p&
&p&& Insert cool sound effects to the video easily via drag & insert feature.&/p&
&p&& Export generated videos to device photo library, email, Facebook or any other installed Apps that support video files such as Dropbox, HEX Editor, RePlay, Video Mux, etc.&/p&
&p&& iOS 7 users can directly share the videos with friends & family via AirDrop feature.&/p&
&p&Now go & show your creativity by creating super cool short videos & share them with your friends!&/p&
&p&Notes:&/p&
&p&& This free version will limit the time to 5 seconds per recording. Please upgrade to full version to unlock the limitation.&/p&
&p&& Please contact us directly at info@push.my for any comments, suggestions or bug reports. We appreciate all comments to enable us to improve this App.&/p&
&p&& We have no way to reply to comments made in the App Store section. Kindly contact us directly as above for any technical issues.&/p&
&p&ENJOY!&/p&
需要 iOS 5.0 或更高版本
aZeR DiLLs
Custom Video Uploader For Vine -
&p&软件介绍&/p&
&p&这个程序允许你直接上传自定义视频到葡萄。用它从过去的分享珍贵时刻或上传你希望第一个自定义的新创作。 我如何使用这个程序? 1。登录使用您的电子邮件,以藤蔓。首先请确认该帐户正在与官方藤的应用程序。 2。从你的相机胶卷或图片库的任何视频。 3。选择裁剪区域并应用可视化过滤器。 4。输入描述,选择一个藤通道,标记您的朋友和张贴在几秒钟您的视频!&/p&
iOS7.0更高版本。与 iPhone、iPod touch、iPad 兼容。
WeiZi Liang
Long Exposure Photography Timer
&p&软件介绍&/p&
&p&Long Exposure Photography Timer is an easy-to-use but essential tool that helps long exposure photographers to calculate the exposure time after attaching neutral density (ND) filter(s).&/p&
&p&Features:&/p&
&p&- Totally free!&/p&
&p&- Simple and intuitive&/p&
&p&- No Internet connection needed&/p&
&p&- Countdown timer for exposures more than 30 seconds&/p&
&p&- Up to 20 ND stops&/p&
需要 iOS 6.0 或更高版本。
Charalampos Sergios (C) Charalampos Sergios
Germany Radio Live (Deutschland - Deutsch / German Radio)
&p&软件介绍&/p&
&p&This Germany Radio Live app is the most simple and comprehensive radio app for D.E. which covers many popular radio channels and stations in Germany.&/p&
&p&One of the great features provided in this app is that this app support multitasking / background mode. This means that you can listen to any of your favorite Germany radio channel and in the mean time, do other stuffs with your device such as reading books and browsing websites.&/p&
&p&Listen, enjoy, and let your favorite radio channels and music accompany you anywhere anytime :D&/p&
&p&The radio channels included in this Germany Radio Live (Deutschland Deutsch / German Radio) app but not limited to are (some will be added in next update):&/p&
&p&Deutschlandradio Kultur 89.6&/p&
&p&Deutschlandfunk 89.1&/p&
&p&hr2 kultur 96.7&/p&
&p&radioeins vom rbb 95.8&/p&
&p&hr1 99.0&/p&
&p&hr4 101.7&/p&
&p&sunshine live 102.1&/p&
&p&hr3 89.3&/p&
&p&mdr info 95.3&/p&
&p&inforadio vom rbb 93.1&/p&
&p&br-klassik 103.2&/p&
&p&bremen eins 93.8&/p&
&p&bayern 3 97.3&/p&
&p&swr3 moose radio 99.6&/p&
&p&fritz vom rbb 102.6&/p&
&p&you fm - young fresh music 106.6&/p&
&p&bayern 1 91.3&/p&
&p&swr2 culture radio 105.7&/p&
&p&swr1 baden-wuerttemberg 94.7&/p&
&p&DASDING 90.8&/p&
&p&Klassik Radio 92.2&/p&
&p&Bayern 2 88.4&/p&
&p&SWR4 Rhineland-Palatine 91.4&/p&
&p&oldiestar&/p&
&p&SWR1 Rhineland-Palatine 87.7&/p&
&p&Star FM Berlin 87.9&/p&
&p&103.7 UnserDing - liebt euch&/p&
&p&SWR4 Baden-Wuerttemberg 90.1&/p&
&p&radio SAW-90er&/p&
&p&ROCK ANTENNE Classic Perlen&/p&
&p&Top 100 Station&/p&
&p&planet more music radio 100.2&/p&
&p&Bremen Vier 101.2&/p&
&p&SR2 Kultur Radio 91.3&/p&
&p&Radio-im-internet.de&/p&
&p&SWR3-Chartshow&/p&
&p&SWR3 DanceNight&/p&
&p&Antenna Niedersachsen Bremen 104.8&/p&
&p&Oldie95 95.0&/p&
&p&Berliner Rundfunk 91.4&/p&
&p&domradio.de 96.75&/p&
&p&FFH Digital - Rock over Germany&/p&
&p&radio SAW 100.1&/p&
&p&ego FM 100.8&/p&
&p&SWR cont.ra info radio 91.5&/p&
&p&ERF Radio 1539&/p&
&p&B5 aktuell 90.0&/p&
&p&HIT Radio FFH 105.1&/p&
&p&radioBERLIN 88,8 vom rbb 88.8&/p&
&p&Kulturradio vom rbb 92.4&/p&
&p&StadtRadio G&ttingen 107.1&/p&
&p&Radio Paloma&/p&
&p&ROCK ANTENNE 87.9&/p&
&p&radio SAW-70er&/p&
&p&radio SAW-80er&/p&
&p&radio ffn 103.1&/p&
&p&Radio Hamburg 103.6&/p&
&p&MDR KLASSIK&/p&
&p&ANTENNE BAYERN 103.3&/p&
&p&RauteMusick.FM Rock&/p&
&p&MDR Th&ringen 93.3&/p&
&p&on3-radio&/p&
&p&ROCK ANTENNE Erding Freising Ebersberg 87.9&/p&
&p&M94.5&/p&
&p&radio SAW-Neuheiten&/p&
&p&Radio UNiCC 102.7&/p&
&p&bigFM Community-Stream&/p&
&p&Fantasy Dance FM 96.7&/p&
&p&ANTENNE BAYERN Top 40&/p&
&p&ANTENNE BAYERN Oldies but Goldies&/p&
&p&Radio Chemnitz 102.1&/p&
&p&TranceBase FM&/p&
&p&Radio Leipzig 91.3&/p&
&p&Radio Heimatmelodie&/p&
&p&Radio Lausitz 107.6&/p&
&p&HouseTime FM&/p&
&p&B5 plus&/p&
&p&Bayernwelle S&dost 89.0&/p&
&p&hardbase FM&/p&
&p&Minimalradio&/p&
&p&Hitradio RTL Sachsen 105.4&/p&
&p&Ballermann Radio&/p&
&p&MDR FIGARO 88.4&/p&
&p&Antenne Niedersachsen - Oldies&/p&
&p&917xfm 91.7&/p&
&p&LandesWelle Thueringen 104.2&/p&
&p&MDR SPUTNIK Insomnia Channel&/p&
&p&MDR SPUTNIK Club Channel&/p&
&p&MDR SPUTNIK Black Channel&/p&
&p&bigFM 89.5&/p&
&p&FFH Digital - Top 40&/p&
&p&FFH Digital - Lounge&/p&
&p&FFH Digital - Schlagerkult&/p&
&p& by RauteMusik.FM&/p&
&p&RauteMusik.FM Main&/p&
&p&RauteMusik.FM Club&/p&
&p&RauteMusik.FM Metal&/p&
&p&98.8 Kiss FM - Raps&/p&
&p&98.8 Kiss FM - R n B&/p&
&p&FREICE&/p&
&p&ROCKLAND SACHSEN-ANHALT 107.2&/p&
&p&Radio Onda Latina&/p&
&p&Absolut HOT&/p&
&p&BlackBeats.FM&/p&
&p&TechnoBase.FM&/p&
&p&RauteMusik.FM HardeR&/p&
&p&RauteMusik.FM Bigcity Beats&/p&
&p&MagicSta&/p&
&p&Radio SAL&U 101.7&/p&
&p&Hirschmilch Radio Psytrance&/p&
&p&Heart FM&/p&
&p&Inn Salzach Welle 93.1&/p&
&p&98.8 Kiss FM&/p&
&p&Antenne MV 88.7&/p&
&p&Deep Pressure Music&/p&
&p&Antenne Niedersachsen - Classic Rock&/p&
&p&Antenne Thueringen 102.2&/p&
&p&Antenne Niedersachsen 80er&/p&
&p&Jam FM 93.6&/p&
&p&Radio B2 104.9&/p&
&p&rs2 94.3&/p&
&p&Antenne Brandenburg vom rbb 99.7&/p&
&p&Chillectro - Dance&/p&
&p&DIE NEUE 107.7&/p&
&p&hr-iNFO Informationsradio 103.9&/p&
&p&DRadio Wissen&/p&
&p&MDR 1 Radio Sachsen 92.2&/p&
&p&RauteMusik.FM Deutschrap&/p&
&p&Ostseewelle MV&/p&
&p&Antenne Niedersachsen 103.8&/p&
&p&Radio Partywelle&/p&
&p&Radio Infinity&/p&
&p&MDR SPUTNIK 104.4&/p&
&p&MDR JUMP 90.4&/p&
&p&NDR N-Joy Top 30&/p&
&p&ROCK ANTENNE Alternative&/p&
&p&ROCK ANTENNE Heavy Metal&/p&
&p&Zappateers Radio&/p&
&p&The Orange Park Radio&/p&
&p&Oldie Radio&/p&
&p&FFH DIgital - Spezial&/p&
&p&Bayern plus 801&/p&
&p&Allhitz Radio&/p&
&p&Radio Santec&/p&
&p&RMN Relax&/p&
&p&RaggaKings Radio&/p&
&p&RauteMusik.FM Funky&/p&
&p&Radio Zwickau 96.2&/p&
&p&RauteMusik.FM House&/p&
&p&RauteMusik.FM ChartHits&/p&
&p&Alpenradio Volksmusik&/p&
&p&Hirschmilch Radio Chillout&/p&
&p&radio SAW-Party&/p&
&p&Club 85&/p&
&p&CoreTime FM&/p&
&p&Antenne Bayern Chillout&/p&
&p&planet radio nightwax&/p&
&p&NDR Kultur Belcanto&/p&
&p&Antenne Bayern Schlagersahne&/p&
&p&Nebelwelten-Radio&/p&
&p&Antenne Bayern Classic Rock Live&/p&
&p&Antenne Bayern 80er Kulthits&/p&
&p&Radio Schlagergarage&/p&
&p&Radio Kinderwelle&/p&
需要 iOS 7.0 或更高版本
Teik Leong Lee (C) Games Dreams
The Frame Camera
&p&软件介绍&/p&
&p&Now you can capture your photo with fun, elegant, attractive and amazing.&/p&
&p&The Frame Camera got all beautiful frames for capture the moment.&/p&
&p&Features:&/p&
&p&- Over 100 frames with types: General, Antique, Fame, Fun, Heart, Flower, Kid, Christmas, Halloween, Diamond and Gold&/p&
&p&- Use your own custom frames&/p&
&p&- Customizable frame transparent, hue color, saturation, and brightness&/p&
&p&- Add filters & effects on your photo&/p&
&p&- Easy sharing to social network&/p&
需要 iOS 6.0 或更高版本。
Ratha Sou (C) 2014 Ratha Sou
Foto Script
&p&软件介绍&/p&
&p&Add words into your photo to add a quote or logo to turn your photo into something even more unique&/p&
需要 iOS 5.1 或更高版本。
Chris Elder (C) All RIghts Reserved
高清互动影音
&p&软件介绍&/p&
&p&既能满足文艺女青年的傲娇又能满足宅男超高荷尔蒙的海量资源播放器! 速度快、可离线、片子多、类别全,所有节目统统搜罗! 追美剧?迷韩剧?品电影?爱动漫?看综艺?唱大戏?盯国剧?...... 这个App超适合,真的可以有哦! 功能 1.海量视频内容,最新电影电视剧,编辑精心收录整理,每日更新 2.支持横竖屏切换,全屏播放,尽享私人视觉盛宴 3.地铁上,排队中,侯餐时,想看就看,精彩不错过!&/p&
iphoneos6.0
&p&软件介绍&/p&
&p&余音是一个内容和设计都极致优美的音乐APP,以纯粹的方式呈现音乐的愉悦感受。&/p&
&p&余音没有任何多余的元素,它的设计宗旨,就是让人能更加舒服、干净的欣赏美妙的音乐。&/p&
&p&它就像诗歌一样优美。是的,余音与你过往所有体验过的音乐APP,都更别致。&/p&
iphoneos6.0
Guangzhou Weitu Information Technology Co.,Ltd
Lens Col Pro
&p&软件介绍&/p&
&p&你是不是经常会看到朋友们有趣的照片?或许他克隆出一个一模一样的兄弟姐妹,或许他把自己的脑袋放到了明星身上,或许他身后伴随一个不同动作的影子,或许他用一组照片讲了一个动人的故事,或许他的几连拍呈现一个美丽的轨迹。其实,你也可以的,赶紧充分发挥想象力,用本软件创作出自己的杰作吧!&/p&
&p&【简介】&/p&
&p&& 基本功能 海量画框&&百余种基本画框(各种简单图形拼接)与几十种特殊画框(心形、星型、菱形等) 拍摄照片或相册照片随意拼 画框小图片位置互换功能&/p&
&p&& 拍照功能 画框可选择整图或分图拍摄 支持多图自动连拍与连拍间隔设置 支持画框尺寸比例调整&/p&
&p&& 效果风格 画框内小图片间可实现完美融合 小图片边距、圆角可调整 画框丰富设计底纹与单色底纹随意选&/p&
&p&& 文本图章 支持文本或标题添加 支持十二种风格的百余个图章添加&/p&
&p&& 保存分享 支持本地保存与图片复制 支持Instagram、Email、Message、Facebook、Twitter、Sina、Flickr、Tumblr传输照片&/p&
iphoneos7.0
&&缩略图数据文件下载
暂无上传数据
技术支持: QQ交流群:。
购买说明:
发源地数据源至少包含云采集类或文件包数据的一种。预览数据仅为部分示例数据,购买云采集类数据源后可获取该源对应的采集规则及所有结构化数据;购买数据包类数据源可下载直接使用。
版权说明:
发源地所有数据源均来自平台用户使用Finndy+采集引擎发布接入,如无意侵犯了您的版权或隐私,请联系发源地客服,我们将尽快处理解决。
数据交付:
我们为用户提供在线数据导出下载、API调用(云采集类数据)、网盘提取和硬盘邮寄多种数据获取方式。建议根据需求灵活选择。注:由于数据商品的特殊性,用户购买后不可申请退款或退换数据。
云采集数据源支持API调用数据,具体方法如下:
接口地址:/api.php(XML/JSON)
请求方法:HTTP GET(登录交易大厅后获取对应TOKEN)
请求参数:
用户该源对应的TOKEN(登录后自动生成)
当前请求返回数据所在总数据中的分页
当前请求返回的最大数据列
返回数据类型/格式
请求请求返回数据的排序方式
请求示例:/api.php?pageindex=0&pagesize=20&datatype=xml&sortby=desc&token=该源对应的TOKEN
二维码用途:使用发源地iOS/Android移动客户端推送最新数据内容。
使用方法:复制如下代码,添加至您网站对应源页面适当区域。
&!-- Finndy Source BEGIN --&
&span id="finndy_source"&&/span&&script type="text/javascript" src="/qrcode/fsource.js?para=4357_24" charset="UTF-8"&&/script&
&!-- Finndy Source END --&
关于发源地
我要买数据
我是供应方
400-035-0510Livecom多方语音数据共享会议平台方案_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Livecom多方语音数据共享会议平台方案
上传于||暂无简介
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
下载文档到电脑,查找使用更方便
还剩9页未读,继续阅读
你可能喜欢21645人阅读
流媒体(6)
&& &现在来分析live555中关于H264的处理部分,主要包括从文件中读取数据进行并进行frame(NALU)的分割,然后对frame进行分片,这些工作都是在frame交给RTP sink之前完成的。接着上篇分析文章(RTP的打包与发送)中提到的MultiFramedRTP::packFrame函数进行分析。
void MultiFramedRTPSink::packFrame() {
if (fOutBuf-&haveOverflowData()) {
//从source中获取下一个frame
fSource-&getNextFrame(fOutBuf-&curPtr(), fOutBuf-&totalBytesAvailable(),
afterGettingFrame, this, ourHandleClosure, this);
&& &getNextFrame是定义在FramedSource中的非虚函数,从source中获取下一个frame,然后调用回调函数afterGettingFrame。afterGettingFrame被定义为静态函数,因为在C++中类成员函数是不能作为回调用函数的。不过这里为什么要用回调函数回?
&& &注意,对于H264来说,上面的fSource并不是MPEGVideoStreamFramer类,因为在 H264VideoRTPSink::continuePlaying()函数中改变了fSource的值。 & &
Boolean H264VideoRTPSink::continuePlaying() {
// First, check whether we have a 'fragmenter' class set up yet.
// If not, create it now:
if (fOurFragmenter == NULL) {
//创建一个辅助类H264FUAFragmenter,用于H264按照RFC3984进行RTP打包
fOurFragmenter = new H264FUAFragmenter(envir(), fSource, OutPacketBuffer::maxSize,
ourMaxPacketSize() - 12/*RTP hdr size*/);
fSource = fOurF
// Then call the parent class's implementation:
return MultiFramedRTPSink::continuePlaying();
&& &fSource被指向了H264FUAFragmenter类,这个类主要实现了H264按照RFC3984进行RTP分包,不过这里的实现每个RTP中最多只包含一个NALU,没有实现组合封包的情形。这个类的继承关系如下:H264FUAFragmenter-&FramedFilter-&FramedSource。很明显,这是一个filter,包装了MPEGVideoStreamFramer类的对像。
&& &先来看来看getNextFrame的实现
void FramedSource::getNextFrame(unsigned char* to, unsigned maxSize,
afterGettingFunc* afterGettingFunc,
void* afterGettingClientData,
onCloseFunc* onCloseFunc,
void* onCloseClientData) {
// Make sure we're not already being read:
if (fIsCurrentlyAwaitingData) {
envir() && &FramedSource[& && this && &]::getNextFrame(): attempting to read more than once at the same time!\n&;
envir().internalError();
//buffer地址
fMaxSize = maxS
//buffer最大长度
fNumTruncatedBytes = 0; // could be changed by doGetNextFrame()
fDurationInMicroseconds = 0; // could be changed by doGetNextFrame()
fAfterGettingFunc = afterGettingF
//获取完一个frame后将执行这个函数
fAfterGettingClientData = afterGettingClientD //这个参数就是MultiFramedRTPSink类型指针
fOnCloseFunc = onCloseF
fOnCloseClientData = onCloseClientD
fIsCurrentlyAwaitingData = T
doGetNextFrame();
&& &上面的函数主要是进行一些成员变量的初始化,获取到的frame需要保存到fTo地址中,然后调用fAfterGettingFunc函数,若文件读取完毕,还需要调用fOnCloseFunc函数。重要的工作还是在doGetNextFrame函数中完成,不过它是定义在FramedSource类中的纯虚函数,需要在子类中重新实现。
&& &现在来看H264FUAFragmenter中对doGetNextFrame的实现
void H264FUAFragmenter::doGetNextFrame() {
if (fNumValidDataBytes == 1) {
//读取一个新的frame
// We have no NAL unit data currently in the buffer.
Read a new one:
fInputSource-&getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,
afterGettingFrame, this,
FramedSource::handleClosure, this);
//现在buffer中已经存在NALU数据了,需要考虑三种情况
//1.一个新的NALU,且足够小能投递给RTP sink。
//2.一个新的NALU,但是比RTP sink要求的包大了,投递第一个分片作为一个FU-A packet, 并带上一个额外的头字节。
//3.部分NALU数据,投递下一个分片作为一个FU-A packet,并带上2个额外的头字节。
// We have NAL unit data in the buffer.
There are three cases to consider:
// 1. There is a new NAL unit in the buffer, and it's small enough to deliver
to the RTP sink (as is).
// 2. There is a new NAL unit in the buffer, but it's too large to deliver to
the RTP sink in its entirety.
Deliver the first fragment of this data,
as a FU-A packet, with one extra preceding header byte.
// 3. There is a NAL unit in the buffer, and we've already delivered some
fragment(s) of this.
Deliver the next fragment of this data,
as a FU-A packet, with two extra preceding header bytes.
if (fMaxSize & fMaxOutputPacketSize) { // shouldn't happen
envir() && &H264FUAFragmenter::doGetNextFrame(): fMaxSize (&
&& fMaxSize && &) is smaller than expected\n&;
fMaxSize = fMaxOutputPacketS
fLastFragmentCompletedNALUnit = T // by default
if (fCurDataOffset == 1) { // case 1 or 2
if (fNumValidDataBytes - 1 &= fMaxSize) { // case 1
//情况1, 处理整个NALU
memmove(fTo, &fInputBuffer[1], fNumValidDataBytes - 1);
fFrameSize = fNumValidDataBytes - 1;
fCurDataOffset = fNumValidDataB
} else { // case 2
//情况2,处理NALU的第1个分片。注意,我们添加FU指示符和FU头字节(with S bit)到包的最前面(
//重用已经存在的NAL 头字节作为FU的头字节)
// We need to send the NAL unit data as FU-A packets.
Deliver the first
// packet now.
Note that we add FU indicator and FU header bytes to the front
// of the packet (reusing the existing NAL header byte for the FU header).
fInputBuffer[0] = (fInputBuffer[1] & 0xE0) | 28; // FU indicator
fInputBuffer[1] = 0x80 | (fInputBuffer[1] & 0x1F); // FU header (with S bit)
重用NALU头字节
memmove(fTo, fInputBuffer, fMaxSize);
fFrameSize = fMaxS
fCurDataOffset += fMaxSize - 1;
fLastFragmentCompletedNALUnit = F
} else { // case 3
//情况3,处理非第1个分片。需要添加FU指示符和FU头(我们重用了第一个分片中的字节,但是需要清除S位,
//并在最后一个分片中添加E位)
// We are sending this NAL unit data as FU-A packets.
We've already sent the
// first packet (fragment).
Now, send the next fragment.
Note that we add
// FU indicator and FU header bytes to the front.
(We reuse these bytes that
// we already sent for the first fragment, but clear the S bit, and add the E
// bit if this is the last fragment.)
fInputBuffer[fCurDataOffset-2] = fInputBuffer[0]; // FU indicator
fInputBuffer[fCurDataOffset-1] = fInputBuffer[1]&~0x80; // FU header (no S bit)
unsigned numBytesToSend = 2 + fNumValidDataBytes - fCurDataO
if (numBytesToSend & fMaxSize) {
// We can't send all of the remaining data this time:
numBytesToSend = fMaxS
fLastFragmentCompletedNALUnit = F
//最后一个分片,需要在FU头中设置E标志位
// This is the last fragment:
fInputBuffer[fCurDataOffset-1] |= 0x40; // set the E bit in the FU header
fNumTruncatedBytes = fSaveNumTruncatedB
memmove(fTo, &fInputBuffer[fCurDataOffset-2], numBytesToSend);
fFrameSize = numBytesToS
fCurDataOffset += numBytesToSend - 2;
if (fCurDataOffset &= fNumValidDataBytes) {
// We're done with this data.
Reset the pointers for receiving new data:
fNumValidDataBytes = fCurDataOffset = 1;
// Complete delivery to the client:
FramedSource::afterGetting(this);
&& &H264FUAFragmenter::doGetNextFrame函数第一次执行时,执行条件1,需要调用 MPEGVideoStreamFramer::doGetNextFrame读取一个新的frame,获取frame的具体过程稍后再分析。现在先看获取frame之后的工作,afterGettingFrame函数
void H264FUAFragmenter::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
H264FUAFragmenter* fragmenter = (H264FUAFragmenter*)clientD
fragmenter-&afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime,
durationInMicroseconds);
没什么好说的,再看afterGettingFrame1函数
void H264FUAFragmenter::afterGettingFrame1(unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
fNumValidDataBytes += frameS
//保存读到的frame长度
fSaveNumTruncatedBytes = numTruncatedB
fPresentationTime = presentationT
fDurationInMicroseconds = durationInM
// Deliver data to the client:
doGetNextFrame();
&& &上面的代码首先记录几个数据到成员变量中,fNumValidDataBytes很重要,表示读取到的frame长度+1。然后又一次调用了H264FUAFragmenter::doGetNextFrame(),这里将进入H264FUAFragmenter::doGetNextFrame函数中第二个条件分支,这种循环调用很容易把人弄迷糊了。
&& &H264FUAFragmenter::doGetNextFrame函数中第二个条件分支中,处理H264的RTP分片问题,这里是按照RFC3984进行RTP封装的。你应该注意到,在上篇文章&RTP的打包与发送&中,也出现了分片的代码(MultiFramedRTPSink::packFrame函数中),那里直接将frame按MTU的长度来拆分。那为什么H264还要自定义一套RTP打包的标准呢?暂时我也不清楚。
&& &在H264FUAFragmenter::doGetNextFrame()最后调用了 FramedSource::afterGetting
void FramedSource::afterGetting(FramedSource* source) {
source-&fIsCurrentlyAwaitingData = F
//表示已经获取到数据了,处于非等待状态
// indicates that we can be read again
// Note that this needs to be done here, in case the &fAfterFunc&
// called below tries to read another frame (which it usually will)
//通过回调用进行后续处理
if (source-&fAfterGettingFunc != NULL) {
(*(source-&fAfterGettingFunc))(source-&fAfterGettingClientData,
source-&fFrameSize, source-&fNumTruncatedBytes,
source-&fPresentationTime,
source-&fDurationInMicroseconds);
&& &上面的代码主要是调用了FramedSource::getNextFrame函数中传递下来的回调函数,这个回调函数就是MultiFramedRTPSink::afterGettingFrame,处理过程在上一篇文章&RTP的打包与发送&中已经分析过了。
&& &现在来看MPEGVideoStreamFramer::doGetNextFrame获取Frame的过程。继承关系:H264VideoStreamFramer-&MPEGVideoStreamFramer-&FramedFilter-&FramedSource。在继承路径中存在FrameFilter,这说明H264VideoStreamFramer包装了其它source(包装的是读取文件的字节流source)。doGetNextFrame函数首先在MPEGVideoStreamFramer中实现。
void MPEGVideoStreamFramer::doGetNextFrame() {
fParser-&registerReadInterest(fTo, fMaxSize); //将目的buffer信息注册到语法分析类中
continueReadProcessing();
//继续进行读数据
&& &这里的MPEGVideoStreamFramer::fParser,是一个MPEGVideoStreamParser类型指针,作为语法分析器。再来看continueReadProcessing函数
void MPEGVideoStreamFramer::continueReadProcessing() {
unsigned acquiredFrameSize = fParser-&parse();
//文件的语法分析(即demux)
if (acquiredFrameSize & 0) {
// We were able to acquire a frame from the input.
// It has already been copied to the reader's space.
fFrameSize = acquiredFrameS
fNumTruncatedBytes = fParser-&numTruncatedBytes();
// &fPresentationTime& should have already been computed.
// Compute &fDurationInMicroseconds& now:
fDurationInMicroseconds
= (fFrameRate == 0.0 || ((int)fPictureCount) & 0) ? 0
: (unsigned)((fPictureCount*1000000)/fFrameRate);
#ifdef DEBUG
fprintf(stderr, &%d bytes @%u.%06d, fDurationInMicroseconds: %d ((%d*1000000)/%f)\n&, acquiredFrameSize, fPresentationTime.tv_sec, fPresentationTime.tv_usec, fDurationInMicroseconds, fPictureCount, fFrameRate);
fPictureCount = 0;
//调用自身的afterGetting函数,因为这不一个&leaf& source, 所以可能直接调用,
//而不用担心出现无限递归
// Call our own 'after getting' function.
Because we're not a 'leaf'
// source, we can call this directly, without risking infinite recursion.
afterGetting(this);
// We were unable to parse a complete frame from the input, because:
// - we had to read more data from the source stream, or
// - the source stream has ended.
&& &函数中首先调用了MPEGVideoStreamParser::parse函数,将一个完整的Frame分析出来,并copy到了fTo(fTo就是OutPacketBuffer中的缓冲区)中,这其中肯定也实现了从文件中读取数据的过程。这里的fNumTruncatedBytes变量需要注意,fNumTruncatedBytes&0的话,表明Frame的实际长度大于fTo的最大长度,这将导致数据丢失,这时就要考虑增加缓冲区的长度了。成功获取一个Frame后,将调用afterGetting函数处理后续工作。
&& &先来看parse函数,parse是定义在MPEGVideoStreamParser中的纯虚函数,在子类H264VideoStreamParser中实现。parse主要是从文件的字节流中,分离出一个个的Frame,对于H264而言其实就是对一个个的NALU。*.264文件的格式非常简单,每个NALU以 0x 作为起始符号(中间的NALU也可以以0x000001作为起始符),顺序存放。
unsigned H264VideoStreamParser::parse() {
//首先找到起始符号, 并跳过。文件流的最开始必需以0x开始,但后续的NALU充许以0x bytes)作为分隔
// The stream must start with a 0x:
if (!fHaveSeenFirstStartCode) {
// Skip over any input bytes that precede the first 0x:
u_int32_t first4B
while ((first4Bytes = test4Bytes()) != 0x) {
get1Byte(); setParseState(); // ensures that we progress over bad data
skipBytes(4); // skip this initial code
setParseState();
fHaveSeenFirstStartCode = T // from now on
//将起始标志也保存到目的缓冲区中
if (fOutputStartCodeSize & 0) {
// Include a start code in the output:
save4Bytes(0x);
//保存所有数据,直至遇到起始标志,或者文件结束符。需要注意NALU中的第一个字节,因为它指示了NALU的类型
// Then save everything up until the next 0x bytes) or 0x bytes), or we hit EOF.
// Also make note of the first byte, because it contains the &nal_unit_type&:
u_int8_t firstB
if (haveSeenEOF()) {
//已经设置了文件结束标志,将剩下的数据保存也来即可
// We hit EOF the last time that we tried to parse this data,
// so we know that the remaining unparsed data forms a complete NAL unit:
unsigned remainingDataSize = totNumValidBytes() - curOffset();
if (remainingDataSize == 0) (void)get1Byte(); // forces another read, which will cause EOF to get handled for real this time
#ifdef DEBUG
fprintf(stderr, &This NAL unit (%d bytes) ends with EOF\n&, remainingDataSize);
if (remainingDataSize == 0) return 0;
firstByte = get1Byte();
//将第一个字节保存下来,其指示了NALU的类型
saveByte(firstByte);
while (--remainingDataSize & 0) {
saveByte(get1Byte());
u_int32_t next4Bytes = test4Bytes();
firstByte = next4Bytes&&24;
//将第一个字节保存下来
//将下一个起始符号之前的数据都保存下来
while (next4Bytes != 0x && (next4Bytes&0xFFFFFF00) != 0x) {
// We save at least some of &next4Bytes&.
if ((unsigned)(next4Bytes&0xFF) & 1) {
//一次可以保存4个字节,并不需要一个一个字节对比,除非到了结尾
// Common case: 0x or 0x000001 definitely doesn't begin anywhere in &next4Bytes&, so we save all of it:
save4Bytes(next4Bytes);
skipBytes(4);
// Save the first byte, and continue testing the rest:
saveByte(next4Bytes&&24);
skipBytes(1);
next4Bytes = test4Bytes();
// Assert: next4Bytes starts with 0x or 0x000001, and we've saved all previous bytes (forming a complete NAL unit).
// Skip over these remaining bytes, up until the start of the next NAL unit:
if (next4Bytes == 0x) {
skipBytes(4);
skipBytes(3);
u_int8_t nal_ref_idc = (firstByte&0x60)&&5;
u_int8_t nal_unit_type = firstByte&0x1F;
#ifdef DEBUG
fprintf(stderr, &Parsed %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\&%s\&))\n&,
curFrameSize()-fOutputStartCodeSize, nal_ref_idc, nal_unit_type, nal_unit_type_description[nal_unit_type]);
//下面根据NALU的类型来作具体的分析
switch (nal_unit_type) {
case 6: { // Supplemental enhancement information (SEI)
analyze_sei_data();
// Later, perhaps adjust &fPresentationTime& if we saw a &pic_timing& SEI payload??? #####
case 7: { // Sequence parameter set (序列参数集)
//保存一份SPS的副本到H264VideoStreamFramer中,后面的pps也需要保存,sps中可能还包含了帧率信息
// First, save a copy of this NAL unit, in case the downstream object wants to see it:
usingSource()-&saveCopyOfSPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);
// Parse this NAL unit to check whether frame rate information is present:
unsigned num_units_in_tick, time_scale, fixed_frame_rate_
analyze_seq_parameter_set_data(num_units_in_tick, time_scale, fixed_frame_rate_flag);
if (time_scale & 0 && num_units_in_tick & 0) {
usingSource()-&fFrameRate = time_scale/(2.0*num_units_in_tick);
//sps中包含了帧率信息
#ifdef DEBUG
fprintf(stderr, &Set frame rate to %f fps\n&, usingSource()-&fFrameRate);
if (fixed_frame_rate_flag == 0) {
fprintf(stderr, &\tWARNING: \&fixed_frame_rate_flag\& was not set\n&);
//sps中不包含帧率信息,则使用source中设置的默认帧率
#ifdef DEBUG
fprintf(stderr, &\tThis \&Sequence Parameter Set\& NAL unit contained no frame rate information, so we use a default frame rate of %f fps\n&, usingSource()-&fFrameRate);
case 8: { // Picture parameter set (图像参数集PPS)
// Save a copy of this NAL unit, in case the downstream object wants to see it:
usingSource()-&saveCopyOfPPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);
usingSource()-&setPresentationTime();
//设置当前的时间
#ifdef DEBUG
unsigned long secs = (unsigned long)usingSource()-&fPresentationTime.tv_
unsigned uSecs = (unsigned)usingSource()-&fPresentationTime.tv_
fprintf(stderr, &\tPresentation time: %lu.%06u\n&, secs, uSecs);
//如果这个NALU是一个VCL NALU(即包含的是视频数据),我们需要扫描下一个NALU的起始符,
//以判断这个NALU是否是当前的&access unit&(这个&access unit&应该可以理解为一帧图像帧吧)。
//我们需要根据这个信息去指明何时该增加&fPresentationTime&(RTP 打包时也需要根据这个信息,决定是否设置&M&位)。
// If this NAL unit is a VCL NAL unit, we also scan the start of the next NAL unit, to determine whether this NAL unit
// ends the current 'access unit'.
We need this information to figure out when to increment &fPresentationTime&.
// (RTP streamers also need to know this in order to figure out whether or not to set the &M& bit.)
Boolean thisNALUnitEndsAccessUnit = F // until we learn otherwise
if (haveSeenEOF()) {
// There is no next NAL unit, so we assume that this one ends the current 'access unit':
thisNALUnitEndsAccessUnit = T
Boolean const isVCL = nal_unit_type &= 5 && nal_unit_type & 0; // Would need to include type 20 for SVC and MVC #####
if (isVCL) {
u_int32_t first4BytesOfNextNALUnit = test4Bytes();
u_int8_t firstByteOfNextNALUnit = first4BytesOfNextNALUnit&&24;
u_int8_t next_nal_ref_idc = (firstByteOfNextNALUnit&0x60)&&5;
u_int8_t next_nal_unit_type = firstByteOfNextNALUnit&0x1F;
if (next_nal_unit_type &= 6) {
//下一个NALU不是VCL的,当前的&access unit&结束了
// The next NAL unit is not a VCL; therefore, we assume that this NAL unit ends the current 'access unit':
#ifdef DEBUG
fprintf(stderr, &\t(The next NAL unit is not a VCL)\n&);
thisNALUnitEndsAccessUnit = T
//下一个NALU也是VCL的,还需要检查一下它们是不是属于同一个&access unit&
// The next NAL unit is also a VLC.
We need to examine it a little to figure out if it's a different 'access unit'.
// (We use many of the criteria described in section 7.4.1.2.4 of the H.264 specification.)
Boolean IdrPicFlag = nal_unit_type == 5;
Boolean next_IdrPicFlag = next_nal_unit_type == 5;
if (next_IdrPicFlag != IdrPicFlag) {
// IdrPicFlag differs in value
#ifdef DEBUG
fprintf(stderr, &\t(IdrPicFlag differs in value)\n&);
thisNALUnitEndsAccessUnit = T
} else if (next_nal_ref_idc != nal_ref_idc && next_nal_ref_idc*nal_ref_idc == 0) {
// nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0
#ifdef DEBUG
fprintf(stderr, &\t(nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0)\n&);
thisNALUnitEndsAccessUnit = T
} else if ((nal_unit_type == 1 || nal_unit_type == 2 || nal_unit_type == 5)
&& (next_nal_unit_type == 1 || next_nal_unit_type == 2 || next_nal_unit_type == 5)) {
// Both this and the next NAL units begin with a &slice_header&.
// Parse this (for each), to get parameters that we can compare:
// Current NAL unit's &slice_header&:
unsigned frame_num, pic_parameter_set_id, idr_pic_
Boolean field_pic_flag, bottom_field_
analyze_slice_header(fStartOfFrame + fOutputStartCodeSize, fTo, nal_unit_type,
frame_num, pic_parameter_set_id, idr_pic_id, field_pic_flag, bottom_field_flag);
// Next NAL unit's &slice_header&:
#ifdef DEBUG
fprintf(stderr, &
Next NAL unit's slice_header:\n&);
u_int8_t next_slice_header[NUM_NEXT_SLICE_HEADER_BYTES_TO_ANALYZE];
testBytes(next_slice_header, sizeof next_slice_header);
unsigned next_frame_num, next_pic_parameter_set_id, next_idr_pic_
Boolean next_field_pic_flag, next_bottom_field_
analyze_slice_header(next_slice_header, &next_slice_header[sizeof next_slice_header], next_nal_unit_type,
next_frame_num, next_pic_parameter_set_id, next_idr_pic_id, next_field_pic_flag, next_bottom_field_flag);
if (next_frame_num != frame_num) {
// frame_num differs in value
#ifdef DEBUG
fprintf(stderr, &\t(frame_num differs in value)\n&);
thisNALUnitEndsAccessUnit = T
} else if (next_pic_parameter_set_id != pic_parameter_set_id) {
// pic_parameter_set_id differs in value
#ifdef DEBUG
fprintf(stderr, &\t(pic_parameter_set_id differs in value)\n&);
thisNALUnitEndsAccessUnit = T
} else if (next_field_pic_flag != field_pic_flag) {
// field_pic_flag differs in value
#ifdef DEBUG
fprintf(stderr, &\t(field_pic_flag differs in value)\n&);
thisNALUnitEndsAccessUnit = T
} else if (next_bottom_field_flag != bottom_field_flag) {
// bottom_field_flag differs in value
#ifdef DEBUG
fprintf(stderr, &\t(bottom_field_flag differs in value)\n&);
thisNALUnitEndsAccessUnit = T
} else if (next_IdrPicFlag == 1 && next_idr_pic_id != idr_pic_id) {
// IdrPicFlag is equal to 1 for both and idr_pic_id differs in value
// Note: We already know that IdrPicFlag is the same for both.
#ifdef DEBUG
fprintf(stderr, &\t(IdrPicFlag is equal to 1 for both and idr_pic_id differs in value)\n&);
thisNALUnitEndsAccessUnit = T
if (thisNALUnitEndsAccessUnit) {
#ifdef DEBUG
fprintf(stderr, &*****This NAL unit ends the current access unit*****\n&);
usingSource()-&fPictureEndMarker = T
//这里就是设置RTP打包时用到的M标志了
++usingSource()-&fPictureC
//下一个NALU不再属于当前&access unit&&时,才改变时间
// Note that the presentation time for the next NAL unit will be different:
struct timeval& nextPT = usingSource()-&fNextPresentationT // alias 这里是引用 
nextPT = usingSource()-&fPresentationT
double nextFraction = nextPT.tv_usec/ + 1/usingSource()-&fFrameR
unsigned nextSecsIncrement = (long)nextF
nextPT.tv_sec += (long)nextSecsI
nextPT.tv_usec = (long)((nextFraction - nextSecsIncrement)*1000000);
setParseState();
return curFrameSize();
} catch (int /*e*/) {
#ifdef DEBUG
fprintf(stderr, &H264VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n&);
// the parsing got interrupted
&& &H264VideoStreamParser::parse()函数除了取出Frame,还对NALU中的部分参数做了解释工作。对于PPS或者SPS类型的NALU,要保存到H264VideoStreamFramer中。&access unit&,在这里可以理解为一副图像,一个&access unit&可以包含多个NALU,很显示这些NALU的时间戳应该是相同的。实际上,很多时候一个&access unit&单元只包含一个NALU,这里简单多了。分析过程是根据section 7.4.1.2.4 of the
H.264 specification进行的。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:451290次
积分:5558
积分:5558
排名:第3038名
原创:95篇
转载:20篇
评论:147条
(1)(1)(1)(7)(1)(1)(2)(1)(5)(1)(5)(13)(13)(14)(5)(11)(14)(1)(5)(12)(1)(1)}

我要回帖

更多关于 live图像数据库下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信