精华内容
下载资源
问答
  • 云媒体
    千次阅读
    2018-02-28 20:31:04

    老习惯先说下背景:

          使用阿里云做音视频处理,转码处理模式有两种:

        主动请求阿里转码服务器获取转码之后数据写库(后续上代码);

        通过阿里云主题回调,转码完成之后主动回调;

    优缺点:主动请求在使用资源的时候才获取阿里云转码数据,如果资源使用率低或者只是个云盘推荐该方法;

                回调需要单独服务器处理阿里云回调,增加服务器压力,容易丢数据;但是数据实时性高;

    直接上核心处理代码(没搞清楚阿里云音视频转码逻辑的可能得多下点功夫看看阿里文档了,这里不赘述)

    /**
         * 处理转码结果通知
         * @param bodyJson
         */
        @Override
        public void handleMediaTranscodingNotice(JSONObject bodyJson, HttpServletResponse response) {
            JSONObject message = JSONObject.fromObject(bodyJson.getString("Message"));
            if(!message.get("Type").equals("Report") || !message.get("State").equals("Success")){
                return ;
            }
            String run_id = message.getString("RunId");
            Map<String,String> messageMap = new HashMap<String,String>();
            JSONObject mediaWorkflowExecution = message.getJSONObject("MediaWorkflowExecution");
            String workFlow = mediaWorkflowExecution.getString("Name");
            if(workFlow.contains("mp3")){
                messageMap = getObjectMapForMp3(message);
            }else{
                messageMap = getObjectMap(message);
            }
            if(!updateRemoteStatus(messageMap)){
                long num = this.springJedisDao.increment("media_notice_error_"+run_id,1);
                if(num > 5){
                    response.setStatus(200);
                    this.springJedisDao.del("media_notice_error_"+run_id);
                    return;
                }
                this.springJedisDao.expire("media_notice_error_"+run_id,24*60*60);
                response.setStatus(500);
            }else{
                response.setStatus(200);
            }
    
        }
    
        //这个接口要优化 by smkk
        private boolean updateRemoteStatus(Map<String, String> map) {
            boolean result = false;
            String key = map.get("key");
            String url = map.get("url");
            String workflow = map.get("workflow");
            String picurl = map.get("pickey");
            String picAttribute = null;
            if(StringUtils.isNotBlank(picurl)){
                picAttribute = getPicInfo(picurl);
            }
            String duration = map.get("duration");
    
            String filePath =map.get("filePath");//OSS 保存的文件 源文件路径
            BaseResp<Object> baseResp = new BaseResp<Object>();
            if(filePath.contains("longbei_media_resource")){
                if(filePath.contains("_video")){
                    url = AppserviceConfig.alimedia_mp4_outurl +"/"+ url;
                }else{
                    url = AppserviceConfig.alimedia_cdnurl + url;
                }
                baseResp = mediaResourceService.updateMediaResourceInfo(key,picurl,url,workflow,duration,picAttribute);
            }else if(filePath.contains("tiku")){
                Double d = Double.parseDouble(duration);
                tikuMongoDao.save(key, d.intValue() ,url);
                result = true;
            }else {
                baseResp = improveService.updateMedia(key,picurl,url,workflow,duration,picAttribute);
            }
            if(baseResp.getCode() == Constant.STATUS_SYS_00){
                result = true;
            }
            return  result;
        }
    
    
        //ActivityList
        public static Map<String,String> getObjectMap(JSONObject json){
            if(json.get("Type").equals("Report")&&json.get("State").equals("Success")){
                Map<String,String> map = new HashMap<>();
    
                JSONObject mediaWorkflowExecution = json.getJSONObject("MediaWorkflowExecution");
                String name = (String)mediaWorkflowExecution.get("Name");
                //通过工作流名称 判断走mp3 还是 mp4
                map.put("workflow",name);
                String mediaId = (String)mediaWorkflowExecution.get("MediaId");
    
                JSONObject jsonObject2 = mediaWorkflowExecution.getJSONObject("Input").getJSONObject("InputFile");
                String objId = jsonObject2.getString("Object");
                String filePath = jsonObject2.getString("Object");
                map.put("filePath",filePath);
                String[] objArr = objId.split("/");
                objId = objArr[objArr.length-1];
                map.put("key",objId);
                JSONArray activityList = mediaWorkflowExecution.getJSONArray("ActivityList");
                //获取截图和文件
                for (int i = 0; i < activityList.size(); i++) {
                    JSONObject j = JSONObject.fromObject(activityList.get(i));
                    if("Snapshot".equals(j.get("Type"))){
                        map.put("pickey",getPicKey(j,objId));
                        continue;
                    }
                    if("Transcode".equals(j.get("Type"))){
                        map.put("url",getFileKey(j,objId));
                        continue;
                    }
                }
                map = getTimeStr(map,mediaId);
                System.out.print("getObjectMap info ="+JSON.toJSON(map).toString());
                return map;
            }
            return null;
        }
    
    
        private static String getFileKey(JSONObject js, String objid){
            String runid = (String)js.get("RunId");
    //        String result = "filekey/"+runid+"/"+ AppserviceConfig.alimedia_mp4_query_mp4+"/"+objid;
            String result = "filekey/"+runid+".mp4";
            return result;
        }
    
        private static String getPicKey(JSONObject js, String objid){
            String runid = (String)js.get("RunId");
            return "pickey/" + runid + ".jpg";
        }
    
        private static String getPicInfo(String picKey){
            String url = AppserviceConfig.alimedia_cdnurl+ picKey +imageInfo;
            String sRequest = HttpUtils.getRequest(url,null);
            if(StringUtils.isBlank(sRequest)){
                return null;
            }
            JSONObject jsonObject = JSONObject.fromObject(sRequest);
            if(null != jsonObject){
                JSONArray jsonArray = new JSONArray();
                JSONObject reJs = new JSONObject();
                JSONObject jHeight = JSONObject.fromObject(jsonObject.get("ImageHeight"));
                JSONObject jWidth = JSONObject.fromObject(jsonObject.get("ImageWidth"));
                reJs.put("height",jHeight.get("value"));
                reJs.put("width",jWidth.get("value"));
                jsonArray.add(reJs);
                return jsonArray.toString();
            }
            return null;
        }
    
        /**
         * mp3 视频转码
         * @param json
         * @return
         */
        private static Map<String,String> getObjectMapForMp3(JSONObject json){
            Map<String,String> map = new HashMap<>();
    
            JSONObject mediaWorkflowExecution = json.getJSONObject("MediaWorkflowExecution");
            String name = (String)mediaWorkflowExecution.get("Name");
            String mediaId = (String)mediaWorkflowExecution.get("MediaId");
            map.put("workflow",name);
    
            JSONObject jsonObject2 = mediaWorkflowExecution.getJSONObject("Input").getJSONObject("InputFile");
            String objId = jsonObject2.getString("Object");
            map.put("filePath",objId);
            String[] objArr = objId.split("/");
            objId = objArr[objArr.length-1];
            map.put("key",objId);
            JSONArray activityList = mediaWorkflowExecution.getJSONArray("ActivityList");
            //获取文件
            for (int i = 0; i < activityList.size(); i++) {
                JSONObject j = JSONObject.fromObject(activityList.get(i));
                if(j.get("State").equals("Success")){
                    map.put("url",getFileForMp3(j,objId));
                    map = getTimeStr(map,mediaId);
    //                JSONObject jsonObject = JSONObject.fromObject(map);
                    break;
                }
            }
            return map;
        }
    
        private static String getFileForMp3(JSONObject js,String objid){
            String runid = (String)js.get("RunId");
    //        String result = "mp3key/"+runid+"/"+AppserviceConfig.alimedia_mp3_query_mp3+"/"+objid;
            String result ="mp3key/"+runid+".mp3";
            return  result;
        }
    
        private static Map<String,String> getTimeStr(Map<String,String> map,String mediaId) {
            String duration = "";
            try{
                QueryMediaListRequest qu = new QueryMediaListRequest();
                qu.setMediaIds(mediaId);
                qu.setAcceptFormat(FormatType.JSON);
                AcsResponse ac = getDefaultAcsClient().getAcsResponse(qu);
                JSONObject js = JSONObject.fromObject(ac);
                JSONArray jsArray = js.getJSONArray("mediaList");
                if(null != jsArray && jsArray.size()>0){
                    JSONObject j = JSONObject.fromObject(jsArray.get(0));
                    duration = (String)j.get("duration");
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            if(!StringUtils.isBlank(duration)){
                Double d = Double.parseDouble(duration);
                map.put("duration",d.intValue()+"");
            }
            return map;
        }
    
        private static DefaultAcsClient getDefaultAcsClient(){
            try{
                if(null == defaultAcsClient){
                    DefaultProfile.addEndpoint("cn-"+AppserviceConfig.alimedia_area,
                            "cn-"+AppserviceConfig.alimedia_area,
                            "Mts",
                            "mts.cn-"+AppserviceConfig.alimedia_area+".aliyuncs.com");
                    DefaultProfile profile = DefaultProfile.getProfile(
                            "cn-"+AppserviceConfig.alimedia_area,
                            AppserviceConfig.alimedia_accessKeyId,
                            AppserviceConfig.alimedia_accessKeySecret);
                    defaultAcsClient = new DefaultAcsClient(profile);
                }
            }catch (Exception e){
            }
            return defaultAcsClient;
        }
    附带了一点业务转码处理,updateRemoteStatus为获取数据之后的处理业务逻辑接口;


    更多相关内容
  • 腾讯多媒体文件处理总结

    千次阅读 多人点赞 2022-06-01 15:42:08
    } } 腾讯云媒体处理官网链接:https://cloud.tencent.com/document/product/436/55672 此处用resttemplate模拟发送http请求到cos服务端,由于官方文档说返回的响应结果是application/xml格式,导致这里有一个小...

    简单记录一下项目中使用cos进行图像、视频处理时遇到的问题和思考总结。

    场景一

     需要根据用户上传的视频自动获取视频封面图片用做视频展示的封面

    场景二

    需要根据用户上传的图片进行压缩处理以节省图片下载时长,减少页面响应时长

    场景三

    后台获取用户上传视频的时长(前端获取的时候无法保证在上传到cos之前及时获取视频时长,所以需要后台通过接口来获取)

    场景四

    前端视频偶现无法下载的情况,

    解决过程:

    一、前置条件:

            在腾讯云控制台开启媒体处理功能(收费),如果要使用cos提供的媒体处理功能,如图片压缩,视频获取指定帧,获取媒体文件元信息等必须要开通该功能,开通媒体服务如下:

     配置媒体文件访问时的跨域问题:

     二、解决过程

            首先,通过后端Http请求的方式获取视频媒体文件的时长,从而限制用户上传的视频不能超过一定时长,代码如下:

    public Boolean checkVideoDuration(String videoUrl) {
            try {
                String reqUrl = videoUrl + "?ci-process=videoinfo";
                log.info("提交检测视频文件url: {}", reqUrl);
                String respStr = restTemplate.getForObject(reqUrl, String.class);
    
                //创建解析XML对象
                XStream xStream = new XStream() {
                    @Override
                    protected MapperWrapper wrapMapper(MapperWrapper next) {
                        return new MapperWrapper(next) {
                            @Override
                            public boolean shouldSerializeMember(Class definedIn, String fieldName) {
                                if (definedIn == Object.class) {
                                    return false;
                                }
                                return super.shouldSerializeMember(definedIn, fieldName);
                            }
                        };
                    }
                };
                xStream.processAnnotations(Response.class);
                @SuppressWarnings("unchecked")
                Response resp = (Response) xStream.fromXML(respStr);
                Double duration = resp.getMediaInfo().getStream().getVideo().getDuration();
                return 120 - duration.intValue() > 0;
            } catch (Exception e) {
                log.error("解析视频信息异常, {}", e);
                return false;
            }
        }

             腾讯云媒体处理官网链接:https://cloud.tencent.com/document/product/436/55672        

            此处用resttemplate模拟发送http请求到cos服务端,由于官方文档说返回的响应结果是application/xml格式,导致这里有一个小插曲,由于当时时间紧,任务急所以就直接找了jackson-xml进行String到JavaBean的格式转换,导致所有的http请求的响应到前端都成了xml格式了,虽然临时通过前端添加Content-Type: application/json的方式解决了,但是还是导致一些没有加的接口返回xml这种不友好的格式,最终采用了xstream的方式进行解析xml字符串到JavaBean的转换;

            然后,就是媒体文件的压缩和获取第一帧的问题,下面是对应的官网文档链接:

    https://cloud.tencent.com/document/product/436/60453

            说说我当时的思考过程,以及实践之后的总结,根据官网的说明,压缩图片可以通过如下的方式进行实现:

    http://example-1258125638.cos.ap-shanghai.myqcloud.com/sample.png?imageMogr2/format/webp

    就是将已经上传的图片生成的链接后面添加imageMogr2/format/webp这种后缀就可以实现,由于当时想的是,由于在官网接口说明中需要Auth String才能通过上面的url方式直接实现压缩,当时我就跟着官网说明查看获取Auth String的方式发现有点繁琐,后面想着对比华为云OBS的文件压缩方式,就直接拿着上面的url链接在浏览器试了一下,发现可以实现压缩,并展示出来压缩的图片,然后保存图片,发现确实图片大小确实小了很多,大功告成;

            接下来看看获取视频指定帧,官方文档链接如下:

    https://cloud.tencent.com/document/product/436/55671

    如官方文档所示,直接在图片url后面添加参数的方式来实现获取截屏帧,如下:

    https://<BucketName-APPID>.cos.<Region>.myqcloud.com/for-test.mp4?ci-process=snapshot&time=1&format=jpg&<Auth String>

    和上面压缩如出一辙,也是需要Auth String,当时也是没唬住了,想办法获取这个Auth String,后来结合之前使用OBS的场景,大胆尝试,发现已经上传的视频,直接在后面添加

    "ci-process=snapshot&time=1&format=jpg"参数,就可以获取视频第一帧的图片了;

            最后,出现在当时已经在云端存储的视频文件,在pc端下载出现失败的情况,除了修改上面的跨域配置之外,如果还开启了cdn全球加速的话,也要吧cdn全球加速、cdn跨域headers配置都设置一下,否则还是会出现下载失败的情况

    总结:

            后来仔细一想,可能我们通过我们的key,scret在上传文件到cos的时候,如果上传成功了,返回的文件url其实就包含我们的bucket,endpoint等信息,这个时候,直接使用这个文件的url去访问媒体处理相关服务的时候,其实这个Auth String的鉴权信息其实已经自动就识别了,可能通过我们的bucket,endpoint等信息就已经不需要再传递Auth String等额外鉴权信息了;

            而且不论阿里的OSS,华为云的OBS,腾讯云的COS,他们的文件url结构都是类似的组装结构,尤其当我们将我们的bucket的读写权限设置成如下公共读的时候,就已经可以直接拿文件的url进行访问相关服务,而不需要重新获取Auth String相关信息了

     

    展开全文
  • 广电云媒体电视平台安全防护建设之道.pdf广电云媒体电视平台安全防护建设之道.pdf广电云媒体电视平台安全防护建设之道.pdf广电云媒体电视平台安全防护建设之道.pdf广电云媒体电视平台安全防护建设之道.pdf广电云媒体...
  • 云媒体服务方式是通信网络中替代传统媒体服务器的发展方向,其主要实现语音、视频以及相关业务应用的媒体处理功能。通过对视频会议产品发展需求的整理,从现有云媒体整体架构出发进行了分析,对通过云媒体的方式实现...
  • 广电云媒体电视平台安全防护建设之道.docx广电云媒体电视平台安全防护建设之道.docx广电云媒体电视平台安全防护建设之道.docx广电云媒体电视平台安全防护建设之道.docx广电云媒体电视平台安全防护建设之道.docx广电...
  • 提出了一种基于云计算的媒体服务器系统架构,提供了一种云媒体服务器的调度方法,并对云媒体的应用前景进行了分析。基于本文所述的云媒体服务器系统,能根据当下的业务流量提供自适应性的性能管理能力,使得由之构建...
  • 行业文档-设计装置-云媒体教学终端.zip
  • 互联网+云媒体智慧平台解决方案
  • 针对传统云媒体资源分配算法中没有考虑整体服务满意度和分配效用等因素对算法性能的影响,导致云媒体资源分配服务效率和可应用性不高的问题,引入云媒体服务提供者和云媒体服务请求者的效用函数模型,从服务价格、...
  • 针对在移动网络中,如何进一步提高云媒体服务带宽利用率的问题,提出一种基于预测机制的云媒体网络自适应视频流选择算法。该算法包含可用带宽预测模型和视频流决策模型。在带宽预测模型中,根据带宽评估结果把当前的...
  • 智能酒店新方向 华曦达科技云媒体平台搭建.docx
  • 云媒体政务融合平台方案.pptx
  • 互联网智慧云媒体平台解决方案.pdf
  • 行业分类-设备装置-云媒体道闸
  • 智慧方案
  • 2.0版本,wordpress 腾讯云媒体库迁移,将本地图片迁移到腾讯云,1.0 的腾讯云升级之后不能使用。
  • 行业文档-设计装置-一种便携式3G网络云媒体农田环境监测仪
  • 手机或平板配合qloud media 使用,通过PC解码,使手机播放存放在电脑上的音频,视频文件。
  • 摘要:近日,在华为TechWave全球技术峰会(人工智能&数据)上,马栏山视频文创产业园首席专家周苏岳受邀发表演讲《经典永流传,媒体 AI 让老电影焕发新生》,分享与华为原生媒体服务合作的媒体AI在老电影修复...
    摘要:近日,在华为云TechWave全球技术峰会(人工智能&数据)上,马栏山视频文创产业园首席专家周苏岳受邀发表演讲《经典永流传,媒体 AI 让老电影焕发新生》,分享与华为云原生媒体服务合作的媒体AI在老电影修复方面的应用。

    本文分享自华为云社区《华为云媒体 AI,实现黑白老电影的彩色梦》,原文作者:音视频大管家 。

    近日,华为云TechWave全球技术峰会(人工智能&数据)在上海成功举办。AI技术分论坛以“AI技术创新,加速行业智能升级”为主题,邀请到行业嘉宾分享了AI在互联网媒体、医疗、环境等行业的落地实践。马栏山视频文创产业园首席专家周苏岳受邀发表演讲《经典永流传,媒体 AI 让老电影焕发新生》,分享与华为云原生媒体服务合作的媒体AI在老电影修复方面的应用。

    华为云围绕马栏山园区企业视频从制作到发布全流程业务场景,搭建了马栏山视频产业云,满足视频生产、制作、分发等各个环节的云服务需求。在修复经典影视领域,通过引入AI修复增强和上色技术,解决胶片及磁带保存劣化及当时拍摄技术限制造成的问题,与纯人工相比,处理速度可提高100+倍;而引入混合云平台,使得计算和存储资源池能够无限动态扩容,极大提升效率,降低成本。

    周苏岳指出,利用媒体AI做老电影的修复,特别是黑白视频上色方面,难度比我们想象的要大很多,以他曾负责的黑白电影《雷锋》上色为例,主要有两大难点:第一、搜索空间大,计算复杂性高;第二、颜色语义信息复杂,模型建立困难。在AI分论坛上,周苏岳表示,要解决这两大难题,主要是运用多GPU并行计算,建立AI自动上色 + 人工矫正 + AI迭代优化上色的自学习迭代上色工艺;另外,形成整体到局部的迭代优化流程,空间尺度上,通过筛选框定点优化局部颜色,时间尺度上,通过颜色传播算法优化连续帧之间的颜色效果。

    马栏山视频文创产业园首席专家周苏岳

    电影《雷锋》的修复,解决了AI神经网络自动学习与上色的3大难题:不同帧之间的颜色时序一致性;单帧图片内的颜色空间协调性;物品对象的颜色语义一致性。周苏岳也坦诚道,AI视频上色还面临很多挑战,比如在运动及光影变化明显时,存在由于焦点不实导致的轮廓识别精度不高而颜色溢出,少部分物品如衣领、红领巾等颜色匹配错误,多人物场景下极少数物品颜色漏上等问题。

    周苏岳还分享了华为云原生媒体服务如何高效地帮助马栏山5G高新视频公共服务云平台在影视剧生产、广电制播及融媒体运营等多场景应用。未来,马栏山视频文创产业园与华为云将进一步加强合作,在筛选框定点优化局部颜色、关键帧颜色传播算法、以及模型层面增加物体追踪及上色约束方面进行针对性攻关,以解决当前AI系统存在的两个主要问题:当前模型在低分辨率图片(480P)上训练不适应高清和4K视频上色;光影变化导致全局灰度变化,颜色相似性变得模糊。预计明年将会有更优秀的AI工艺生产的经典影视作品跟大家见面。

    华为深耕音视频领域30多年,拥有1000多项音视频算法专利,在5G、IT基础设施、智能终端、芯片等方面全栈领先。华为云原生媒体服务,在老旧视频修复和标清/高清视频的超高清转置方面,有着丰富的经验,目前已与国内多家媒体平台以及产业园区达成合作,得到业界的广泛认可。未来云上内容制作正在成为趋势,华为云原生媒体服务将持续深耕影视制作领域,为推进中国影视工业数字化升级、促进整个电影产业发展打造坚实的云服务平台。

    在近日举办的华为云TechWave云原生媒体服务专题日上,华为云原生视频服务正式升级为华为云原生媒体服务,专题日深度解读三大产品领域-“媒体生产”,“媒体分发”,以及“媒体应用”。看华为三十年媒体技术积累如何为传统业务赋予新的竞争力,拓展新赛道,激活行业生产力。点击链接了解更多云原生媒体服务干货看点。https://www.huaweicloud.com/about/techwave_video.html

    点击关注,第一时间了解华为云新鲜技术~

    展开全文
  • 媒体云大数据平台整体解决方案
  • 基于混合架构生产和发布相结合的CMS 生产CMS部署在私有...技术创新点三 基于混合架构生产和发布相结合的CMS 基于融合媒体云的内容交互系统 在平台统一的用户管理和运维管理下支持市区县各级用户一对一一对多
  • 媒体融合生产与分发平台(基于架构和敏捷生产的中央厨房)融媒体.ppt媒体融合生产与分发平台(基于架构和敏捷生产的中央厨房)融媒体.ppt媒体融合生产与分发平台(基于架构和敏捷生产的中央厨房)融媒体.ppt媒体融合...
  • 智能审核服务是—个Al标记+人脑确认复核的复合工作。 通过智能识别手段也就是Al , 对视频中被认为可能出现的间 题进行标注 , 并提交给用户进行确认辨别,同时人工需要根据实际审核的需要,确认复核范围井完成复核...
  • 提出一种媒体资源池云化中的多租户资源调度、负载均衡实现技术及流程,介绍了云媒体在IMS业务平台中的应用方案、云媒体资源技术的实验情况,并对云媒体商业模式等进行了阐述,为推动本土软硬件云媒体服务器生产商及...
  • 通过华为实现RTMP流媒体推流拉流

    千次阅读 2021-09-14 22:33:21
    准备直播工具 1、下载并安装推流工具... 拉流 打开vlc点击“媒体”“打开网络串流”输入拉流地址。 rtmp://pull.hwvideo.hwcloudlive.com/live/test  最终效果 参考 三分钟体验直播服务_视频直播 Live_快速入门_华为云

    准备直播工具

    1、下载并安装推流工具OBS
    2、下载并安装播放工具VLC

    推流

    1、运行OBS工具,单击界面左下角的“文件”选择“设置”。


    2、在左侧菜单栏选择“输出”,将“输出模式”选择“高级”,“关键帧间隔”配置为2。 

    3、在左侧菜单栏选择“推流”,“服务”选择“自定义”,输入“服务器”和“串流密钥”。单击“确定”,完成推流地址的配置。

    rtmp://push.hwvideo.hwcloudlive.com/live/


    4、 点击开始推流。

    拉流

    打开vlc点击“媒体”“打开网络串流”输入拉流地址。

    rtmp://pull.hwvideo.hwcloudlive.com/live/test

     最终效果

     参考

    三分钟体验直播服务_视频直播 Live_快速入门_华为云

    展开全文
  • 媒体智能化信息传播平台建设方案
  • 阿里云媒体转码MTS使用教程

    千次阅读 2017-09-11 11:32:16
    媒体转码(ApsaraVideo for Media Transcoding)是为多媒体数据提供的转码计算服务。它以经济、弹性和高可扩展的音视频转换方法,将多媒体数据转码成适合在PC、TV以及移动终端上播放的格式。适用于音视频网站、在线...
  • 游戏产业链:上游包括游戏开发商(研发能力强,提供内容输出)、云计算厂商(具有IDC资源,提供算力支持)、软硬件 厂商(提供CPU/GPU硬件与软件配套解决方案);中游为游戏运营商或系统设备提供商;下游为终端...
  • 智慧方案

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,876
精华内容 42,750
关键字:

云媒体