短视频批量混剪-经验漫谈

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: “批量生产”、“快速裂变”和“去重”是制作营销短视频的关键,基于有限数量的基础素材大规模生成指定数量的新视频,是营销短视频创作的常见思路。本篇主要介绍一些经验方法,助您更快更高效地生产优质短视频。

“批量生产”、“快速裂变”和“去重”是制作营销短视频的关键,基于有限数量的基础素材大规模生成指定数量的新视频,是营销短视频创作的常见思路。本篇主要介绍一些经验方法,助您更快更高效地生产优质短视频。

概述

背景

进入5G时代,越来越多的商家选择短视频平台做营销推广,将广告制作成短视频投放在多个短视频营销号。

随着短视频内容的发展,视频生产的质量和效率已经越来越重要,本文从理论入手,介绍短视频生产中的方法和经验,本方案的示例基于智能媒体服务IMS,并附有示例代码,帮助大家更快上手短视频的批量合成。

目标读者

有短视频批量制作的商家,或视频批量生产工具的开发者。

方案介绍

先来看一个示例

生产此视频的素材是一段文字和一批视频,将文字转成人声朗读和字幕,再和视频进行合成

文字:

“人们懂得用五味杂陈形容人生,因为懂得味道是每个人心中固守的情怀。在这个时代,每一个人都经历了太多的苦痛和喜悦,人们总会将苦涩藏在心里,而把幸福变成食物,呈现在四季的餐桌之上”

视频:image

这是一个非常常见的营销短视频,当策略敲定好后,通过替换素材、特效、文字,可批量生产出大量视频,从而达到批量生产的目的。

视频生产大概分“设计剧本-素材挑选-视频合成”几个步骤,我们来依次介绍其中的技巧:

1、分镜时长

视频中一个场景镜头我们称之为“分镜”,一个分镜长度不易超过3s,特别是在一个15s的短视频中,过长的分镜会让用户视觉疲劳,一般在电影中一个分镜也在2~3s左右。

如果剪辑中对分镜的时长没有特殊要求,可以对素材随机截取2s来使用,不足2s的取原素材时长。

image

2、素材卡点

上面的示例中,广告词转换后的人声,每句话对应一个视频素材,视频的开始结束时间正好卡在一句话的开始和结束,整个视频更有节奏感。

短视频虽然短,但一般也会有一个故事主线,可以是一段广告词或一段卡点音乐,一句话的朗读大约在2~3s,也正好贴合一个分镜的时长,人声-字幕-素材时间点完全对应,效果往往更好。

MPS智能生产接口提供了文字转语音、语音识别、音乐节奏检测能力,方便用户根据一个原始素材生产出故事主线。素材卡点的整体流程:

根据文字生成卡点:image

根据卡点截取素材,并将截取后的视频素材放到时间线中

image

补充音乐、特效、转场,并合成成片

image

3、素材挑选

上面讲到了一个分镜的时长为2~3s,如果素材是由C端用户上传,或者运营采集的,建议加一个强限制,输入的素材时长不能短于2s,这样免去后续很多适配的麻烦。

实际上,2~3s的视频采集并不是难事,无论是拍摄美食、萌宠、还是街边,一个合理的运镜能采集到很好的一段短素材。

以下面这段素材为例,时长足够长,无论从第几秒开始截取,无论截取几秒,都是一个不违和的内容,不用担心对截取会对素材有影响。

4、准备模板

除了广告词和卡点音乐,还有一种剧本是来源于模板,客户会准备一些模板(如:美食类、探店类、萌宠类),合成时把素材填充进模板进行合成。

和前面提到的相同,合成时根据模板的要求,对素材进行截取。比如一个模板分别需要一个1s、2s、3s的素材,那就把素材分别进行截取,填充到模板中。

如果模板中需要一个3s的素材,但输入的最长素材是2s怎么办呢?

一般可以准备多套模板,分别适配多种时长的场景,当有素材输入时,根据素材时长挑选到合适的模板进行合成即可。image

综上,一个好的生产流程是:

先对素材进行挑选,挑选出足够多的时长合适的素材,根据素材挑选合适的剧本,用剧本来对素材进行截取,然后合成。按照这个流程来制作,逻辑清晰、效果好、代码简洁

相反的做法是: 用户上传的素材多种多样,业务方根据用户素材做大量复杂的适配,这样投入产出比低。无论是广告词,还是模板,对故事主线做了修改,效果都会大打折扣。

方案实施

下面介绍前面示例短视频的代码示例。

整体流程:

1、根据文字素材,调用MPS智能生产接口,生成人声音频和文字卡点

2、根据文字卡点截取视频素材,生成时间线,调用剪辑接口,合成成片

3、重复2,合成多条视频

接口说明

提供文字转语音、人声识别、节奏检测等能力

输入Timeline和成片地址,提交剪辑合成作业,返回剪辑作业JobId

示例代码

/**
Maven引入:

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.5.3</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>ice20201109</artifactId>
    <version>1.2.0</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>mts20140618</artifactId>
    <version>3.3.33</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>
*/


package com.aliyun.ice.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.abs.common.util.MD5Util;
import com.aliyun.ice20201109.Client;
import com.aliyun.ice20201109.models.GetMediaProducingJobRequest;
import com.aliyun.ice20201109.models.GetMediaProducingJobResponse;
import com.aliyun.ice20201109.models.SubmitMediaProducingJobRequest;
import com.aliyun.ice20201109.models.SubmitMediaProducingJobResponse;
import com.aliyun.mts20140618.models.QueryIProductionJobRequest;
import com.aliyun.mts20140618.models.QueryIProductionJobResponse;
import com.aliyun.mts20140618.models.SubmitIProductionJobRequest;
import com.aliyun.mts20140618.models.SubmitIProductionJobResponse;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.teaopenapi.models.Config;
import com.google.common.io.CharStreams;
import org.apache.commons.io.Charsets;
import org.apache.logging.log4j.util.Strings;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Create by oushu
 * Date 2021/12/7 上午9:28
 */
public class BatchProduceTTSSubtitleRelease {

    private String accessKeyId;
    private String accessKeySecret;
    private OSS ossClient;
    private String bucket;
    private String regionId;
    private com.aliyun.mts20140618.Client mpsClient;

    public void initClient() throws Exception {
        accessKeyId = "your_ak";
        accessKeySecret = "your_sk";
        bucket = "your-bucket";
        regionId = "cn-shanghai";
        ossClient = createOssClient();
        mpsClient = createMpsClient();
    }

    public static void main(String[] args) throws Exception {
        BatchProduceTTSSubtitleRelease batchProduceVideo = new BatchProduceTTSSubtitleRelease();
        batchProduceVideo.initClient();
        batchProduceVideo.batchProduceVideo();
    }

    public void batchProduceVideo() throws Exception {
        // 文字素材
        String text = "人们懂得用五味杂陈形容人生,因为懂得味道是每个人心中固守的情怀。在这个时代,每一个人都经历了太多的苦痛和喜悦,人们总会将苦涩藏在心里,而把幸福变成食物,呈现在四季的餐桌之上";

        // 视频素材
        List<String> videoUrlList = new ArrayList();
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_1.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_2.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_3.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_4.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_5.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_6.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_7.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_8.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_9.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_10.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_11.mp4");
        videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_12.mp4");

        // 背景音乐
        String bgMusic = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/demo/music/generated_6_good.wav";

        // 字幕样式设置
        Integer fontSize = 45;
        String fontName = "WenQuanYi Zen Hei Mono";
        String fontColor = "#FFFFFF";

        // 视频尺寸
        Integer width = 720;
        Integer height = 1280;

        // logo
        String logoUrl = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your-logo.png";
        Integer logoX = 20;
        Integer logoY = 20;

        String title = "这里是标题";
        String subTitle = "这里是副标题";

        // 成片数量
        int targetCount = 2;
        // 每次提交一个任务,业务方根据需要更换不同参数提交多次
        produceSingleVideo(text, videoUrlList, title, subTitle, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height, targetCount);
    }

    // 提交单个任务
    public void produceSingleVideo(String text, List<String> videoUrls, String title, String subtitle, String bgMusic, int fontSize, String fontName, String fontColor,
                                   String logoUrl, Integer logoX, Integer logoY, int width, int height, int targetCount) throws Exception {
        // 提交MPS任务,文字生成语音和字幕
        String voice = "zhichu";
        String jobParams = "{\"voice\":\"" + voice + "\",\"format\":\"mp3\",\"sample_rate\":16000}";
        String textObject = "iproduction/20211214/" + MD5Util.getMd5String(text) + ".txt";
        text = text.replaceAll(",", "。"); // AsyncTextToSpeech任务用句号进行断句
        putObjectContent(textObject, text);
        String input = "oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + textObject;
        System.out.println("input : " + input);

        SubmitIProductionJobRequest submitIProductionJobRequest = new SubmitIProductionJobRequest();
        submitIProductionJobRequest.setFunctionName("AsyncTextToSpeech");
        submitIProductionJobRequest.setInput(input);
        submitIProductionJobRequest.setOutput("oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/20220617/{source}-{sequenceId}.{resultType}");

        submitIProductionJobRequest.setJobParams(jobParams);
        SubmitIProductionJobResponse submitIProductionJobResponse = mpsClient.submitIProductionJob(submitIProductionJobRequest);
        System.out.println("submit mps response : " + JSONObject.toJSONString(submitIProductionJobResponse.body));

        // 等待任务完成
        String jobId = submitIProductionJobResponse.body.jobId;
        String result;
        while (true) {
            QueryIProductionJobRequest queryIProductionJobRequest = new QueryIProductionJobRequest();
            queryIProductionJobRequest.setJobId(jobId);
            QueryIProductionJobResponse queryIProductionJobResponse = mpsClient.queryIProductionJob(queryIProductionJobRequest);
            System.out.println("job info : " + JSONObject.toJSONString(queryIProductionJobResponse.body));
            if ("Success".equals(queryIProductionJobResponse.body.state)) {
                result = queryIProductionJobResponse.body.result;
                break;
            }
            Thread.sleep(5000);
        }

        // 获取生成的音频和字幕
        JSONObject resultObj = JSONObject.parseObject(result);
        String dataString = resultObj.getString("Data");
        System.out.println("data : " + dataString);

        String audioObject = null;
        String subtitleObject = null;
        JSONObject dataObject = JSONObject.parseObject(dataString);
        JSONArray array = dataObject.getJSONArray("result");
        for (Object obj : array) {
            JSONObject jsonObject = (JSONObject)obj;
            String object = jsonObject.getString("file");
            if (object.endsWith("mp3")) {
                audioObject = object;
            } else if (object.endsWith("txt")) {
                subtitleObject = object;
            }
        }
        System.out.println("audioObject : " + audioObject);
        System.out.println("subtitleObject : " + subtitleObject);

        // 获取字幕内容
        String subtitleContent = getObjectContent(subtitleObject);
        System.out.println("subtitleContent : " + subtitleContent);

        // 组装字幕轨
        if (fontSize <= 0) {
            fontSize = 32;
        }
        if (Strings.isBlank(fontName)) {
            fontName = "WenQuanYi Zen Hei Mono";
        }
        if (Strings.isBlank(fontColor)) {
            fontColor = "#000000";
        }

        for (int j = 0; j < targetCount; j++) {
            // 每次循环将视频素材随机,并提交合成任务
            Collections.shuffle(videoUrls);

            JSONArray subtitleTrackClips = new JSONArray();
            JSONArray mpsSubtitles = JSONArray.parseArray(subtitleContent);
            JSONArray videoTrackClips = new JSONArray();

            // 字幕距离底部距离
            float subtitleBottom = 0.25f;
            // 随机特效,更多特效见:https://help.aliyun.com/document_detail/207059.html
            List<String> vfxs = Arrays.asList("heartfireworks", "colorfulradial", "meteorshower", "starry", "colorfulstarry", "moons_and_stars", "flyfire", "starexplosion", "spotfall", "sparklestarfield");
            // 随机转场,更多转场见:https://help.aliyun.com/document_detail/204853.html
            List<String> transitions = Arrays.asList("windowslice", "displacement", "bowTieVertical", "linearblur", "waterdrop", "polka", "wiperight", "gridflip", "hexagonalize", "windowblinds", "风车");
            float transDuration = 0.3f;
            Collections.shuffle(vfxs);
            for (int i = 0; i < mpsSubtitles.size(); i++) {
                JSONObject mpsSubtitle = mpsSubtitles.getJSONObject(i);
                String content = mpsSubtitle.getString("text");
                content = content.replaceAll("。", "");
                Float timelineIn = mpsSubtitle.getFloat("begin_time") / 1000;
                Float timelineOut = mpsSubtitle.getFloat("end_time") / 1000;
                String subtitleClip = "{\"Content\":\"" + content + "\",\"TimelineIn\":" + timelineIn + ",\"TimelineOut\":" + timelineOut +
                        ",\"Type\":\"Text\",\"X\":0.0,\"Y\":" + subtitleBottom + ",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"FontSize\":" + fontSize +
                        ",\"FontColor\":\"" + fontColor + "\",\"OutlineColour\":\"#000000\",\"FontColor\":\"#ffffff\",}";
                subtitleTrackClips.add(JSONObject.parseObject(subtitleClip));

                // 根据字幕轨,截取视频轨片段
                float out = timelineOut - timelineIn;
                // 随机特效
                String vfx = vfxs.get(i % vfxs.size());
                String transition = transitions.get(i % transitions.size());
                String url = videoUrls.get(i % videoUrls.size());
                JSONObject clip = new JSONObject();
                clip.put("MediaURL", url);
                if (url.endsWith(".jpg")) {
                    clip.put("Duration", out + transDuration);
                    clip.put("Type", "Image");
                } else {
                    clip.put("Out", out + transDuration);
                }
                JSONArray effects = new JSONArray();
                // 添加背景模糊
                effects.add(JSONObject.parseObject("{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}"));
                // 添加氛围类特效
                effects.add(JSONObject.parseObject("{\"Type\":\"VFX\",\"SubType\":\"" + vfx + "\"}"));
                // 视频静音
                effects.add(JSONObject.parseObject("{\"Type\":\"Volume\",\"Gain\":0}"));
                // 添加转场
                effects.add(JSONObject.parseObject("{\"Type\":\"Transition\",\"SubType\":\"" + transition + "\",\"Duration\":"+transDuration+"}"));

                clip.put("Effects", effects);
                videoTrackClips.add(clip);
            }

            if (title != null && title.length() > 0) {
                float titleY = 280;
                int titleFontSize = 70;
                String titleFont = "AlibabaPuHuiTi";
                String titleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + titleY + ",\"Font\":\"" + titleFont + "\",\"Content\":\"" + title + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + titleFontSize + ",\"FontColor\":\"#FFD700\",\"Outline\":4,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}";
                subtitleTrackClips.add(JSONObject.parse(titleClip));
            }
            if (subtitle != null && subtitle.length() > 0) {
                float subtitleY = 200;
                int subtitleFontSize = 60;
                String subtitleFont = "AlibabaPuHuiTi";
                String subtitleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + subtitleY + ",\"Font\":\"" + subtitleFont + "\",\"Content\":\"" + subtitle + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + subtitleFontSize + ",\"FontColorOpacity\":1,\"FontColor\":\"#ffffff\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":false,\"Italic\":false,\"Underline\":false}}";
                subtitleTrackClips.add(JSONObject.parse(subtitleClip));
            }

            // 组装音频轨
            String audioUrl = "http://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + audioObject;
            String audioTrackClips = "";
            if (Strings.isBlank(bgMusic)) {
                audioTrackClips = "[{\"MediaURL\":\"" + audioUrl + "\"}]";
            } else {
                // 两个音频轨,一个人声,一个音乐
                audioTrackClips = "[{\"MediaURL\":\"" + audioUrl + "\"}]},{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]";
            }

            // 图片轨,用于展示logo
            String logoClip = "";
            int logoWidth = 200;
            int logoHeight = 60;
            if (Strings.isNotBlank(logoUrl)) {
                logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":"
                        + logoY + ",\"Width\":\"" + logoWidth + "\",\"Height\":\"" + logoHeight + "\"}";
            }

            // 拼时间线
            String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
                    "\"SubtitleTracks\":[{\"SubtitleTrackClips\":" + subtitleTrackClips.toJSONString() + "}]," +
                    "\"AudioTracks\":[{\"AudioTrackClips\":" + audioTrackClips + "}]," +
                    "\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}";
            System.out.println("timeline : " + timeline);

            // 提交合成任务
            SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
            submitMediaProducingJobRequest.setTimeline(timeline);
            String outputPath = IceUtil.getRandomOutputPath();
            String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4";
            submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}");
            Client iceClient = TestClientInstance.getInstance().getIceClient();
            SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
            System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);

            // 等待合成任务完成
            while (true) {
                GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
                getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
                GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
                System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
                String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
                if ("Success".equals(status)) {
                    break;
                }
                Thread.sleep(5000);
            }
            System.out.println("Produce succeed : " + mediaURL);
        }

    }
    public com.aliyun.mts20140618.Client createMpsClient() throws Exception {
        String accessKeyId = TestClientInstance.getInstance().getAk();
        String accessKeySecret = TestClientInstance.getInstance().getSk();
        Config config = new Config()
                .setAccessKeyId(accessKeyId)
                .setAccessKeySecret(accessKeySecret);
        config.endpoint = "mts." + regionId + ".aliyuncs.com";
        return new com.aliyun.mts20140618.Client(config);
    }

    public OSS createOssClient() {
        String endpoint = "http://oss-" + regionId + ".aliyuncs.com";
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        return ossClient;
    }

    public String getObjectContent(String object) throws Exception {
        OSSObject obj = ossClient.getObject(bucket, object);
        InputStream stream = obj.getObjectContent();
        String result = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
        return result;
    }

    public com.aliyun.ice20201109.Client createIceClient() throws Exception {
        Config config = new Config()
                .setAccessKeyId(accessKeyId)
                .setAccessKeySecret(accessKeySecret);
        config.endpoint = "ice." + regionId + ".aliyuncs.com";
        return new com.aliyun.ice20201109.Client(config);
    }

    public void putObjectContent(String object, String content) throws Exception {
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, object, new ByteArrayInputStream(content.getBytes()));
        ossClient.putObject(putObjectRequest);
    }
}

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
9天前
|
开发者
提升用户黏性:现成体育直播源码开发设计哪些关键功能
面对激烈的市场竞争,如何通过关键功能设计提升用户黏性,使之成为用户长期依赖的首选平台,是每一个开发者必须深思的问题。如下参考“东莞梦幻网络科技”现成体育直播源码,为了吸引更多用户并提高他们的黏性,开发哪些关键功能,帮助实现这一目标:
|
前端开发 机器人
赛事比分直播系统程序 快至三天搭建上线开发解决方案
采用东莞梦幻网络科技独创研发体育比分直播系统平台,功能齐全,支持各类赛事直播/比分预测/赛程数据/比分数据/赛事情报/赛事社区/微短视频/新闻话题/会员中心等模块功能。采用PHP+JAVA+VUE+Object-c的技术语言开发,PC+H5+Android+IOS多端程序。
赛事比分直播系统程序 快至三天搭建上线开发解决方案
《淘宝内容.2017 淘宝从追求效率的交易平台升级成为追求乐趣的内容化社区化的消费媒体平台》电子版地址
淘宝内容.2017 淘宝从追求效率的交易平台升级成为追求乐趣的内容化社区化的消费媒体平台
54 0
《淘宝内容.2017 淘宝从追求效率的交易平台升级成为追求乐趣的内容化社区化的消费媒体平台》电子版地址
|
缓存 算法 数据库
在线直播系统源码,围绕缓存做了哪些工作?
在线直播系统源码,围绕缓存做了哪些工作?
|
大数据 API 数据库
短视频软件开发,短视频常用到的多种集群方式
短视频软件开发的请求处理分为两种方式,分布式部署或者集群管理,集群的应用有多种形式,其中最常见的是基于UDP协议的集群管理,它响应速度快,同时又能快速处理用户的请求,除了该类集群管理外,还有一些其他常用的集群方式,我们一起来看一下。
110 0
|
编解码 分布式计算 搜索推荐
直播内容自动化审核实践
当今短视频、视频直播正如火如荼进行时,沉淀多年的语音直播也正迎来最大的风口。虽然语音直播未来发展的潜力巨大,但现实中也面临着诸多挑战。语音直播审核、个性化语音内容则是挑战中最紧迫的两项。 接下来我们逐一分析并给出我们的解决方案。
854 0
直播内容自动化审核实践
|
编解码 数据安全/隐私保护
一对一直播系统,用户的使用体验从哪些方面提升
一对一直播系统,用户的使用体验从哪些方面提升
239 0
|
视频直播
直播系统的开发中怎么样做才会更好的引流
你也知道流量在这个时代就是代表着钱,可你却不知道如何引流,直播系统已成为现在当之无愧的流量平台大户,想要从这里面“搞点”收益,那你就得好好看看这篇文章,兴许你与成功就差这一点。
直播系统的开发中怎么样做才会更好的引流