Java编码


***【在线视频教程】***

好文章,来自【福优学苑@音视频+流媒体】

创建数据库:db_webavtc

创建数据表:avcategory(素材类别)

id int primary key,


pid int ,


cname varchar(255),


cmemo varchar(1000)


 


CREATE TABLE `avcategory` (


`id` INT(11) NOT NULL AUTO_INCREMENT,


`pid` INT(11) NOT NULL,


`cname` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`cmemo` VARCHAR(1000) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


PRIMARY KEY (`id`) USING BTREE


)


COLLATE='utf8_general_ci'


ENGINE=InnoDB


;


 


创建数据表:avtemplate(转码模板)

Id int primary key auto_increment,


tcTemplateId  varchar(64),


tcTemplateName varchar(64),


tcFormatType  int,//0:m3u8, 1:mp4, 2:flv


threadsNum int,//转码线程数


hlsSegmentTime int, //m3u8的切片长度(秒)


isMultiOutput int,


hasWaterMark int,


Priority int,


removeAV int,//去除视频(0),去除音频(1)


waterMark varchar(2048),//水印json串


tcTemplateDetails varchar(4096)//转码模板的json串


 


CREATE TABLE `avtemplate` (


`id` INT(11) NOT NULL AUTO_INCREMENT,


`tcTemplateId` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcTemplateName` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcTemplateEnglish` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcFormatType` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`isDeleted` INT(11) NULL DEFAULT '0',


`state` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`threadsNum` INT(11) NULL DEFAULT '0',


`hlsSegmentTime` INT(11) NULL DEFAULT '10',


`tcFastMode` INT(11) NULL DEFAULT '0',


`isMultiOutput` INT(11) NULL DEFAULT '0',


`tcOutputFileCount` INT(11) NULL DEFAULT '0',


`hasWaterMark` INT(11) NULL DEFAULT '0',


`priority` INT(11) NULL DEFAULT '0',


`waterMark` VARCHAR(2048) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcTemplateDetails` VARCHAR(4096) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`createTime` DATETIME NULL DEFAULT NULL,


`removeAV` INT(11) NULL DEFAULT '0',


`isSystemReserved` INT(11) NULL DEFAULT '0',


PRIMARY KEY (`id`) USING BTREE,


INDEX `idx_by_name` (`tcTemplateName`) USING BTREE,


INDEX `idx_by_tcid` (`tcTemplateId`) USING BTREE


)


COLLATE='utf8_general_ci'


ENGINE=InnoDB


ROW_FORMAT=COMPACT


AUTO_INCREMENT=43


;


 


 


创建数据表:avassets(素材)

 


Id int primary key auto_increment,


avAssetsGuid varchar(255),


avSrcName  varchar(500),


avTitle  varchar(255),


avMakeFullName  varchar(500),


avType int,


avCategoryId int,


avState  int,


avTag   varchar(255),


avPoster  varchar(255),


tcTemplateId  varchar(64)


 


 


 


 


 


 


创建数据表:avtranscodetask(转码任务)

 


CREATE TABLE `avtranscodetask` (


`id` INT(11) NOT NULL AUTO_INCREMENT,


`tcTaskGuid` VARCHAR(128) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`avAssetsGuid` VARCHAR(128) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcTaskOutDir` VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcTaskOutName` VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcTaskState` INT(11) NULL DEFAULT NULL,


`tcTaskPercent` VARCHAR(128) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`tcConsumeTime` INT(11) NULL DEFAULT NULL,


`tcTranscoderIP` VARCHAR(128) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


PRIMARY KEY (`id`) USING BTREE


)


COLLATE='utf8_general_ci'


ENGINE=InnoDB


;


 


 


 


 


 


 


 


 


 


bean

创建AVCategory

创建AVTemplate

创建AVAssets

创建AVTranscodeTask

 


 


 


 


 


 


dao

AVCategoryDaoImpl

AVTemplateDaoImpl

AVAssetsDaoImpl

AVTrancodeTaskDaoImpl

 


 


service

AVCategoryService

 


AVCategoryServiceImpl

AVTemplateService

 


AVTemplateServiceImpl

 


AVAssetsService

 


AVAssetsServiceImpl

 


AVTrancodeTaskService

 


AVTrancodeTaskServiceImpl

 


 


 


 


action

 


AVCategoryAction

 


AVTemplateAction

稍微复杂,一点一点改造


 


 


AVAssetsAction

AVTrancodeTaskAction

 


 


 


UI

 


avcategoryList.jsp


avtemplateList.jsp


 


avassetsMother.jsp


 


文件上传的组件:webuploader.js


 


avassetsEdit.jsp:添加素材


avassetsEdit2.jsp: 编辑素材


avassetsAddNew.action


avassetsList.jsp:素材列表


 


 


avtranscodetaskList.jsp:转码列表


 


 


 


 


配置文件

Struts.xml:            action


applicationContext.xml:   *.hbm.xml,  beans


 


 


 


 


 


 


创建数据表: ctype


CREATE TABLE `ctype` (


`ctid` INT(11) NOT NULL AUTO_INCREMENT,


`ctname` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`ctcode` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`ctno` INT(11) NULL DEFAULT NULL,


`ctdesc` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',


`csCount` INT(11) NULL DEFAULT NULL,


`pid` INT(11) NULL DEFAULT NULL,


PRIMARY KEY (`ctid`) USING BTREE


)


COLLATE='utf8_general_ci'


ENGINE=InnoDB


AUTO_INCREMENT=14


;


db_webavtc


 


 


左侧导航树

 


ztree


 


 


 


 


Java调用ffmpeg进行转码

 


import java.io.BufferedInputStream;


import java.io.BufferedReader;


import java.io.File;


import java.io.FileInputStream;


import java.io.FileNotFoundException;


import java.io.IOException;


import java.io.InputStreamReader;


import java.io.UnsupportedEncodingException;


 


public class JavaFFmpeg extends Thread{


private boolean stoped = false;




 


 


public boolean isStoped() {


return stoped;


}


 


 


public void setStoped(boolean stoped) {


this.stoped = stoped;


}


 


 


public void run() {  


        // 在run方法中编写需要执行的操作  


stoped = false;


 openFFmpegExe();


 stoped = true;


 


}  


 


 


public static String readToString(String fileName) {


        String encoding = "UTF-8";


        File file = new File(fileName);


        Long filelength = file.length();


        byte[] filecontent = new byte[filelength.intValue()];


        try {


            FileInputStream in = new FileInputStream(file);


            in.read(filecontent);


            in.close();


        } catch (FileNotFoundException e) {


            e.printStackTrace();


        } catch (IOException e) {


            e.printStackTrace();


        }


        try {


            return new String(filecontent, encoding);


        } catch (UnsupportedEncodingException e) {


            System.err.println("The OS does not support " + encoding);


            e.printStackTrace();


            return null;


        }


    }




public static void main(String[] args) {


System.out.println("hello,ffmpeg......");


        


// 在main方法(线程)中,创建线程对象,并启动线程.  


JavaFFmpeg objTC = new JavaFFmpeg();  


objTC.start();  


String strFileContent;


        while( !objTC.isStoped() ){


         try {


Thread.sleep(1000);


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


        


         strFileContent = readToString("d:/_movies/__test/ande_302.mp4.txt");


//        frame=。


         int nIdxFrameStart = strFileContent.lastIndexOf("frame=");


         if(nIdxFrameStart >= 0){


          int nIdxFrameEnd = strFileContent.indexOf((char)0x0A, nIdxFrameStart);


          if(nIdxFrameEnd > 0){


           String strFrames = strFileContent.substring(nIdxFrameStart, nIdxFrameEnd);


           System.out.println(strFrames);// 打印输出信息


          


           /// out_time=00:00:02.066576


              int nIdxOutTimeStart = strFileContent.indexOf("out_time=", nIdxFrameEnd);


              if(nIdxOutTimeStart > 0){


               int nIdxOutTimeEnd = strFileContent.indexOf((char)0x0A, nIdxOutTimeStart);


               if(nIdxOutTimeEnd > 0){


                   String strOutTime = strFileContent.substring(nIdxOutTimeStart, nIdxOutTimeEnd);


                   System.out.println(strOutTime);// 打印输出信息


                  }


              }


              


          }          


         }


        


        }


        


        


        System.out.println("bye,ffmpeg......");


    }






//调用其他的可执行文件,例如:自己制作的exe,或是 下载 安装的软件.


    private void openFFmpegExe() {


    Runtime rn = Runtime.getRuntime();


    Process p = null;


    try {


     ///ffmpeg.exe  -re  -i d:/_movies/ande10.mp4  -vcodec libx264  -acodec aac  -f flv  rtmp://192.168.0.104/hls1/test


     p = rn.exec("ffmpeg431.exe -progress d:/_movies/__test/ande_302.mp4.txt  -i d:/_movies/__test/ande_302.mp4 -threads 1  -vcodec libx264 -acodec aac  -y d:/_movies/__test/ande_302_test2.mp4" );


      


     BufferedInputStream in = new BufferedInputStream(p.getErrorStream());


         BufferedReader inBr = new BufferedReader(new InputStreamReader(in));


         String lineStr;


         System.out.println("开始转码");


         while((lineStr = inBr.readLine())!=null){


        


          //获得命令执行后在控制台的输出信息


          //System.err.println("获得命令执行后在控制台的输出信息");


          /////System.out.println(lineStr);// 打印输出信息


         }


         


         // 检查命令是否执行失败。


         if(p.waitFor()!=0){


         if(p.exitValue()==1)//p.exitValue()==0表示正常结束,1:非正常结束


          System.err.println("命令执行失败!");


         }


         inBr.close();in.close();


         


         


    } catch (Exception e) {


     System.out.println("Error exec:" + e.getMessage());


    }


    }


}


 


spring定时器

 


spring定时器一般有两种:


 


TimerTask、Quartz。


 


1.定时执行任务的类继承TimerTask:


 


Java代码


public class EmailReportTask extends TimerTask{     


    @Override     


    public void run() {     


        System.out.println(" EmailReportTask Run... ");  


    }       


}  


 


 


 


2.spring的配置文件:


 


Xml代码


   <!--  Bean  -->   


<bean id="emailReportTask" class="com.fyl.spring.timertask.EmailReportTask" />  


  


<!-- ScheduledTimerTask设置定时器属性 : period=定时器周期;delay=延迟多久启动   


     86400000代表24个小时;timerTask=执行定时任务的类对象  -->   


<bean id="emailReportScheduleReportTask"   


    class="org.springframework.scheduling.timer.ScheduledTimerTask">     


    <property name="timerTask" ref="emailReportTask" />     


    <property name="period" value="2000" />     


    <property name="delay" value="1000" />     


</bean>   


 


  


    <!-- Spring的TimerFactoryBean负责启动定时任务;   


        scheduledTimerTasks = 需要启动的定时器任务的列表-->  


    <bean class="org.springframework.scheduling.timer.TimerFactoryBean">     


    <property name="scheduledTimerTasks">     


        <list>  


            <ref bean="emailReportScheduleReportTask"/>    


        </list>    


    </property>     


</bean>   


 


 


<!-- ........................................ -->


<!-- ........................................ -->


<!-- ...................spring.timer..................... -->


<bean id="tcTimerTaskScheduler001" class="com.fyl.ssh.timer.TCTimerTaskScheduler">




</bean>


<bean id="scheduled_tcTimerTaskScheduler001" class="org.springframework.scheduling.timer.ScheduledTimerTask">


<property name="delay" value="1000" />


<property name="period" value="5000" />


<property name="timerTask" ref="tcTimerTaskScheduler001" />


</bean>






<bean class="org.springframework.scheduling.timer.TimerFactoryBean">


<property name="scheduledTimerTasks">


<list>


<ref bean="scheduled_tcTimerTaskScheduler001" />


</list>


</property>


</bean>


 


转码任务调度


查询“素材表”:等待状态

1.avassets: 


avType:  0视频,1音频, 2图片


avState:  <=100等待,101:转码中, 200:转码完成, 500:转码失败


 


2.avassets:素材绑定模板 


 


3.avassets:查询对应模板的详细内容,根据tcTemplateGuid


AVAssetsAction


需要添加一个属性:AVTemplateService,需要在spring配置文件中配置


 


4.解析模板信息


(1)String------>Class


com.alibaba.fastjson.JSON


strAVTemplateString


Class obj = JSON.parseObject(strAVTemplateString, AVTemplateDetail.class);


 


(2)String--->JsonArray


JSONArray templateDetailJsonArray = new JSONArray();


templateDetailJsonArray =


JSONArray.parseArray(avtTmp.getTcTemplateDetails());


for(int i = 0; i < templateDetailJsonArray.size(); i++){


AVTemplateDetail avtDetail =


JSON.parseObject(templateDetailJsonArray.getString(i) , AVTemplateDetail.class);


System.out.println(":::"+ avtDetail.getvCodec() );


}


 


5.准备转码


(1)先在数据表中插入一条记录


定时器,每5秒钟,执行一次


avAssets: 检测 avState==101,转码中。


如果有,跳过本地timer;否则,继续开启新转码


(2)构造转码命令,开始转码,并更新转码进度


 


final public static String THE_TC_FFMPEG_CMDLINE_SINGLE =


"ffmpeg431  -i %s -vcodec %s -s %dx%d -acodec %s   -f %s -y  %s";


 


 


6.获取音视频素材的媒体基本信息


基本信息、视频信息、音频信息 ...


 


ffprobe431 -v quiet -print_format json -show_format


 -show_streams  D:\_movies\__test\ande_302_test2.mp4


 


ffprobe431 -i D:\_movies\__test\ande_302_test2.mp4


 


 


 


7.更新转码进度


(1)获取totalDuration


(2)获取实时转码进度,并转成百分比,更新数据库


(3)刷新转码列表页面


 


8.多码流输出


性能很高:只需要一次解码,同时进行多路编码


 


 


9.m3u8转码


切片命令行:


ffmpeg431.exe -i ande_302.mp4   


-vbsf  h264_mp4toannexb -vcodec libx264 -acodec aac


-strict -2 -s 640x480  -r 30  -g 150  -start_number 0  -hls_time 5  -hls_list_size


0   -threads 1   -f hls   -y aaa.m3u8


 


-vbsf  h264_mp4toannexb -vcodec libx264 -acodec aac


-strict -2 -s 960x540  -r 30  -g 150  -start_number 0  -hls_time 5  -hls_list_size


0   -threads 1   -f hls   -y aaa.m3u8


 


 


-vbsf  h264_mp4toannexb -vcodec libx264 -acodec aac


-strict -2 -s 1280x720  -r 30  -g 150  -start_number 0  -hls_time 5  -hls_list_size


0   -threads 1   -f hls   -y aaa.m3u8


 


 


 


10.添加水印(图片、文字)


 


ffmpeg431.exe -i ande_302.mp4 -vf "drawtext=fontfile=simhei.ttf:text='hello, 您 好ffmpeg':x=(mod(2*n\,w+tw)-tw):y=10:fontcolor=#FF6600:fontsize=60" -f mp4 -y


ande_test_text3.mp4


 


11.水印:中文乱码


 


加上盘符后的表达式为


这个郁闷头疼: 


原始语法:-vf drawtext="fontfile='d\:/_movies/__test/simhei.ttf':text=’xxx’"


Java语法:


String strXXX = “-vf drawtext=\"fontfile='d\\://_movies/__test/simhei.ttf’:text=’xxx’\"”;


 


 


Fontconfig error: Cannot load default config file


[Parsed_drawtext_0 @ 0102d840] Using "C:/WINDOWS/fonts/mingliub.ttc"


 


 


ffmpeg431  -i f:/fzavms1/fxhttp_out//__avsrc//2020/10/16/2020101614355828787ef9e22-0131-4777-b7a8-d063bc8d0b4b.mp4  -vf  "drawtext=fontfile='d\:/_movies/__test/simhei.ttf':text='284378sxxxdqqq啊啊啊':x=(mod(2*n\,w+tw)-tw):y=10:fontcolor=#FF6600:fontsize=60"  -vcodec libx264 -s 640x360 -acodec aac -threads  1  -f mp4 -y  f:/fzavms1/fxhttp_out//__tasks//2020/10/16/2020101614355828787ef9e22-0131-4777-b7a8-d063bc8d0b4b.mp4/first.mp4


 


ffmpeg431  -i f:/fzavms1/fxhttp_out//__avsrc//2020/10/16/2020101614355828787ef9e22-0131-4777-b7a8-d063bc8d0b4b.mp4  -vf  "drawtext=fontfile='d\:/_movies/__test/simhei.ttf':text='284378sxxxdqqq啊啊啊':x=(mod(2*n\,w+tw)-tw):y=10:fontcolor=#FF6600:fontsize=60"  -vcodec libx264 -s 640x360 -acodec aac -threads  1  -f mp4 -y  f:/fzavms1/fxhttp_out//__tasks//2020/10/16/2020101614355828787ef9e22-0131-4777-b7a8-d063bc8d0b4b.mp4/first.mp4


 


fastjson


String strWMJsonStr = JSON.toJSONString(objWaterMark, true);


 


WaterMark avtWaterMarkDetail = JSON.parseObject(strxxx , WaterMark.class);


 


 



好文章,来自【福优学苑@音视频+流媒体】
***【在线视频教程】***