如何在linux下载服务器搭建搭建一个猫池

博客访问: 835761
博文数量: 1495
博客积分: 38
博客等级: 民兵
技术积分: 5833
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: C/C++
原文地址: 作者:
本环境的搭建旨在测试IOS &http streaming的测试,进一步探求通过此方式支持实时流的可能性。
一、 ffmpeg的编译和移植:
./configure --enable-gpl --enable-nonfree --enable-pthreads --enable-libfaac --enable-libmp3lame --enable-libx264
make && make install
这里编译的过程需要安装libfaac, libmp3lame, libx264这三个第三方开源编码库。
二、 安装好ffmpeg后,需要准备符合IOS规定的码流,将码流转码成音频为mp3,视频为h264的编码方式,这里需要说明的是,IOS支持p,audio和video解码器都是IOS硬件加速当中提供的,因而不需要你对bitrate、schannel、bitrate等进行转换。
ffmpeg -i ~/Videos/1.ts &-f mpegts -acodec libmp3lame -ar 48000 -ab 64k -s
-vcodec libx264 sample.ts
获取到符合的码流以后,需要对码流进行segment。
三、 Segment
Ios规定的支持http streaming的方式是由一个索引文件(后缀为.m3u8)和相关分段文件决定的,其中m3u8当中的内容如下:
#EXT-X-TARGETDURATION:3
#EXTINF:9,
http://192.168.1.13/./index_dentry/video-1.ts
#EXTINF:7,
http://192.168.1.13/./index_dentry/video-2.ts
#EXTINF:7,
http://192.168.1.13/./index_dentry/video-3.ts
#EXTINF:4,
http://192.168.1.13/./index_dentry/video-4.ts
#EXT-X-ENDLIST
其实就是每个index的url的集合:
Segment.c和Makefile在我的附件当中,因为segment.c是基于ffmpeg去开发的,所以需要你把ffmpeg和segment放在平行目录当中(具体看Makefile调用关系)
./live_segmenter –i
分配好以后发现segment时间长度不一致,这是为什么呢,因为H264解码的关系,为了保证每一个segment文件都可以正常播放,因而segment文件的第一个视频帧肯定是key_frame(这样的做法有待商榷)。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <float.h>
#include <math.h>
#include "libavformat/avformat.h"
#include "libavutil/opt.h"
#define MAX_LENGTH 1024
typedef struct iputargs_t{
&&&&char input[MAX_LENGTH];
&&&&char output_prefix[MAX_LENGTH];
&&&&char output[MAX_LENGTH];
}iputargs_t;
static iputargs_t input_args;
//----------------------------------------------------------------
// fopen_utf8
static FILE *
fopen_utf8(const char * filename, const char * mode)
&&&&FILE * file = NULL;
&&&&file = fopen(filename, mode);
&&&&return file;
static AVStream *add_output_stream(AVFormatContext *output_format_context, AVStream *input_stream) {
&&&&AVCodecContext *input_codec_context;
&&&&AVCodecContext *output_codec_context;
&&&&AVStream *output_stream;
&&&&output_stream = avformat_new_stream(output_format_context, NULL);
&&&&if (!output_stream) {
&&&&&&&&fprintf(stderr, "Could not allocate stream\n");
&&&&&&&&exit(1);
&&&&output_stream->id = 0;
&&&&input_codec_context = input_stream->codec;
&&&&output_codec_context = output_stream->codec;
&&&&output_codec_context->codec_id = input_codec_context->codec_id;
&&&&output_codec_context->codec_type = input_codec_context->codec_type;
&&&&output_codec_context->codec_tag = input_codec_context->codec_tag;
&&&&output_codec_context->bit_rate = input_codec_context->bit_rate;
&&&&output_codec_context->extradata = input_codec_context->extradata;
&&&&output_codec_context->extradata_size = input_codec_context->extradata_size;
&&&&if(av_q2d(input_codec_context->time_base) * input_codec_context->ticks_per_frame > av_q2d(input_stream->time_base) && av_q2d(input_stream->time_base) < 1.0/1000) {
&&&&&&&&output_codec_context->time_base = input_codec_context->time_base;
&&&&&&&&output_codec_context->time_base.num *= input_codec_context->ticks_per_frame;
&&&&else {
&&&&&&&&output_codec_context->time_base = input_stream->time_base;
&&&&switch (input_codec_context->codec_type) {
&&&&&&&&case AVMEDIA_TYPE_AUDIO:
&&&&&&&&&&&&output_codec_context->channel_layout = input_codec_context->channel_layout;
&&&&&&&&&&&&output_codec_context->sample_rate = input_codec_context->sample_rate;
&&&&&&&&&&&&output_codec_context->channels = input_codec_context->channels;
&&&&&&&&&&&&output_codec_context->frame_size = input_codec_context->frame_size;
&&&&&&&&&&&&if ((input_codec_context->block_align == 1 && input_codec_context->codec_id == CODEC_ID_MP3) || input_codec_context->codec_id == CODEC_ID_AC3) {
&&&&&&&&&&&&&&&&output_codec_context->block_align = 0;
&&&&&&&&&&&&}
&&&&&&&&&&&&else {
&&&&&&&&&&&&&&&&output_codec_context->block_align = input_codec_context->block_align;
&&&&&&&&&&&&}
&&&&&&&&&&&&break;
&&&&&&&&case AVMEDIA_TYPE_VIDEO:
&&&&&&&&&&&&output_codec_context->pix_fmt = input_codec_context->pix_fmt;
&&&&&&&&&&&&output_codec_context->width = input_codec_context->width;
&&&&&&&&&&&&output_codec_context->height = input_codec_context->height;
&&&&&&&&&&&&output_codec_context->has_b_frames = input_codec_context->has_b_frames;
&&&&&&&&&&&&if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
&&&&&&&&&&&&&&&&output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
&&&&&&&&&&&&}
&&&&&&&&&&&&break;
&&&&default:
&&&&&&&&break;
&&&&return output_stream;
typedef struct SMSegmentInfo
&&&&unsigned int index;
&&&&double duration;
&&&&char * filename;
} TSMSegmentInfo;
typedef struct SMPlaylist
&&&&/* a ring buffer of segments */
&&&&TSMSegmentInfo * buffer;
&&&&/* maximum number of segments that can be stored in the ring buffer */
&&&&unsigned int bufferCapacity;
&&&&/* index of the first segment on the ring buffer */
&&&&unsigned int first;
&&&&/* how many segments are currently in the ring buffer */
&&&&unsigned int count;
&&&&/* shortcuts */
&&&&unsigned int targetDuration;
&&&&char * httpPrefix;
&&&&/* playlist file used for non-live streaming */
&&&&FILE * file;
} TSMPlaylist;
static char *
duplicateString(const char * str)
&&&&/* unfortunately strdup isn't always available */
&&&&size_t strSize = strlen(str) + 1;
&&&&char * copy = (char *) malloc(strSize);
&&&&memcpy(copy, str, strSize);
&&&&return copy;
static TSMPlaylist *
createPlaylist(const unsigned int max_segments,
&&&&&&&&&&&&&&&const unsigned int target_segment_duration,
&&&&&&&&&&&&&&&const char * http_prefix)
&&&&TSMPlaylist * playlist = (TSMPlaylist *) malloc(sizeof(TSMPlaylist));
&&&&memset(playlist, 0, sizeof(TSMPlaylist));
&&&&if (max_segments)
&&&&&&&&playlist->buffer = (TSMSegmentInfo *) malloc(sizeof(TSMSegmentInfo) *
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&max_segments);
&&&&playlist->bufferCapacity = max_segments;
&&&&playlist->targetDuration = target_segment_duration;
&&&&playlist->httpPrefix = duplicateString(http_prefix);
&&&&return playlist;
static void
updateLivePlaylist(TSMPlaylist * playlist,
&&&&&&&&&&&&&&&&&&&const char * playlistFileName,
&&&&&&&&&&&&&&&&&&&const char * outputFileName,
&&&&&&&&&&&&&&&&&&&const unsigned int segmentIndex,
&&&&&&&&&&&&&&&&&&&const double segmentDuration)
&&&&unsigned int bufferIndex = 0;
&&&&TSMSegmentInfo * nextSegment = NULL;
&&&&TSMSegmentInfo removeMe;
&&&&memset(&removeMe, 0, sizeof(removeMe));
&&&&assert(!playlist->file);
&&&&if (playlist->count == playlist->bufferCapacity)
&&&&&&&&/* keep track of the segment that should be removed */
&&&&&&&&removeMe = playlist->buffer[playlist->first];
&&&&&&&&/* make room for the new segment */
&&&&&&&&playlist->first++;
&&&&&&&&playlist->first %= playlist->bufferCapacity;
&&&&&&&&playlist->count++;
&&&&/* store the new segment info */
&&&&bufferIndex = ((playlist->first + playlist->count - 1) %
&&&&&&&&&&&&&&&&&&&playlist->bufferCapacity);
&&&&nextSegment = &playlist->buffer[bufferIndex];
&&&&nextSegment->filename = duplicateString(outputFileName);
&&&&nextSegment->duration = segmentDuration;
&&&&nextSegment->index = segmentIndex;
&&&&/* live streaming -- write full playlist from scratch */
&&&&playlist->file = fopen_utf8(playlistFileName, "w+b");
&&&&if (playlist->file)
&&&&&&&&unsigned int i, j;
&&&&&&&&const TSMSegmentInfo * first = &playlist->buffer[playlist->first];
&&&&&&&&char tmp[1024] = { 0 };
&&&&&&&&snprintf(tmp,
&&&&&&&&&&&&&&&&&sizeof(tmp),
&&&&&&&&&&&&&&&&&"#EXTM3U\n"
&&&&&&&&&&&&&&&&&"#EXT-X-TARGETDURATION:%u\n"
&&&&&&&&&&&&&&&&&"#EXT-X-MEDIA-SEQUENCE:%u\n",
&&&&&&&&&&&&&&&&&playlist->targetDuration,
&&&&&&&&&&&&&&&&&first->index);
&&&&&&&&fwrite(tmp, strlen(tmp), 1, playlist->file);
&&&&&&&&for ( i = 0; i < playlist->count; i++)
&&&&&&&&&&&j = ((playlist->first + i) %
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&playlist->bufferCapacity);
&&&&&&&&&&&&
&&&&&&&&&&&&const TSMSegmentInfo * segment = &playlist->buffer[j];
&&&&&&&&&&&&snprintf(tmp,
&&&&&&&&&&&&&&&&&&&&&sizeof(tmp),
&&&&&&&&&&&&&&&&&&&&&"#EXTINF:%u,\n%s%s\n",
&&&&&&&&&&&&&&&&&&&&&(int)(segment->duration + 0.5),
&&&&&&&&&&&&&&&&&&&&&playlist->httpPrefix,
&&&&&&&&&&&&&&&&&&&&&segment->filename);
&&&&&&&&&&&&fwrite(tmp, strlen(tmp), 1, playlist->file);
&&&&&&&&// snprintf(tmp, sizeof(tmp), "#EXT-X-ENDLIST\n");
&&&&&&&&// fwrite(tmp, strlen(tmp), 1, playlist->file);
&&&&&&&&fclose(playlist->file);
&&&&&&&&playlist->file = NULL;
&&&&&&&&fprintf(stderr,
&&&&&&&&&&&&&&&&"Could not open m3u8 index file (%s), "
&&&&&&&&&&&&&&&&"no index file will be created\n",
&&&&&&&&&&&&&&&&playlistFileName);
&&&&if (removeMe.filename)
&&&&&&&&/* remove the oldest segment file */
&&&&&&&&remove(removeMe.filename);
&&&&&&&&free(removeMe.filename);
static void
updatePlaylist(TSMPlaylist * playlist,
&&&&&&&&&&&&&&&const char * playlistFileName,
&&&&&&&&&&&&&&&const char * segmentFileName,
&&&&&&&&&&&&&&&const unsigned int segmentIndex,
&&&&&&&&&&&&&&&const int segmentDuration)
&&&&if (playlist->bufferCapacity > 0)
&&&&&&&&/* create a live streaming playlist */
&&&&&&&&updateLivePlaylist(playlist,
&&&&&&&&&&&&&&&&&&&&&&&&&&&playlistFileName,
&&&&&&&&&&&&&&&&&&&&&&&&&&&segmentFileName,
&&&&&&&&&&&&&&&&&&&&&&&&&&&segmentIndex,
&&&&&&&&&&&&&&&&&&&&&&&&&&&segmentDuration);
&&&&&&&&/* append to the existing playlist */
&&&&&&&&char tmp[1024] = { 0 };
&&&&&&&&if (!playlist->file)
&&&&&&&&&&&&playlist->file = fopen_utf8(playlistFileName, "w+b");
&&&&&&&&&&&&snprintf(tmp,
&&&&&&&&&&&&&&&&&&&&&sizeof(tmp),
&&&&&&&&&&&&&&&&&&&&&"#EXTM3U\n"
&&&&&&&&&&&&&&&&&&&&&"#EXT-X-TARGETDURATION:%u\n",
&&&&&&&&&&&&&&&&&&&&&playlist->targetDuration);
&&&&&&&&&&&&fwrite(tmp, strlen(tmp), 1, playlist->file);
&&&&&&&&if (!playlist->file)
&&&&&&&&&&&&fprintf(stderr,
&&&&&&&&&&&&&&&&&&&&"Could not open m3u8 index file (%s), "
&&&&&&&&&&&&&&&&&&&&"no index file will be created\n",
&&&&&&&&&&&&&&&&&&&&playlistFileName);
&&&&&&&&snprintf(tmp,
&&&&&&&&&&&&&&&&&sizeof(tmp),
&&&&&&&&&&&&&&&&&"#EXTINF:%u,\n%s%s\n",
&&&&&&&&&&&&&&&&&segmentDuration,
&&&&&&&&&&&&&&&&&playlist->httpPrefix,
&&&&&&&&&&&&&&&&&segmentFileName);
&&&&&&&&fwrite(tmp, strlen(tmp), 1, playlist->file);
&&&&&&&&fflush(playlist->file);
static void
closePlaylist(TSMPlaylist * playlist)
&&&&if (playlist->file)
&&&&&&&&/* append to the existing playlist */
&&&&&&&&char tmp[1024] = { 0 };
&&&&&&&&snprintf(tmp, sizeof(tmp), "#EXT-X-ENDLIST\n");
&&&&&&&&fwrite(tmp, strlen(tmp), 1, playlist->file);
&&&&&&&&fclose(playlist->file);
&&&&&&&&playlist->file = NULL;
static void
releasePlaylist(TSMPlaylist ** playlistRef)
&&&&TSMPlaylist * playlist = *playlistRef;
&&&&closePlaylist(playlist);
&&&&unsigned int i ;
&&&&for (i = 0; i < playlist->bufferCapacity; i++)
&&&&&&&&TSMSegmentInfo * segmentInfo = &playlist->buffer[i];
&&&&&&&&if (segmentInfo->filename)
&&&&&&&&&&&&free(segmentInfo->filename);
&&&&free(playlist->buffer);
&&&&free(playlist->httpPrefix);
&&&&free(playlist);
&&&&*playlistRef = NULL;
typedef struct SMPacketLink
&&&&/* packet start time in seconds */
&&&&double timeStamp;
&&&&/* the packet */
&&&&AVPacket packet;
&&&&/* a link to the next packet */
&&&&struct SMPacketLink * next;
} TSMPacketLink;
typedef struct SMPacketList
&&&&TSMPacketLink * head;
&&&&TSMPacketLink * tail;
&&&&unsigned int size;
} TSMPacketList;
typedef struct SMStreamLace
&&&&TSMPacketList ** streams;
&&&&unsigned int numStreams;
} TSMStreamLace;
static TSMPacketLink *
createLink(const AVPacket * packet, double timeStamp)
&&&&TSMPacketLink * link = (TSMPacketLink *) malloc(sizeof(TSMPacketLink));
&&&&link->timeStamp = timeStamp;
&&&&link->next = NULL;
&&&&memcpy(&link->packet, packet, sizeof(AVPacket));
&&&&return link;
static void
fifoPush(TSMPacketList * packets, const AVPacket * packet, double timeStamp)
&&&&TSMPacketLink * link = createLink(packet, timeStamp);
&&&&if (!packets->head)
&&&&&&&&assert(!packets->tail);
&&&&&&&&assert(!packets->size);
&&&&&&&&packets->head = link;
&&&&&&&&packets->tail = link;
&&&&&&&&packets->size = 1;
&&&&&&&&/* attach at the tail */
&&&&&&&&assert(packets->size > 0);
&&&&&&&&packets->tail->next = link;
&&&&&&&&packets->tail = link;
&&&&&&&&packets->size++;
static int
fifoPop(TSMPacketList * packets, AVPacket * packet)
&&&&TSMPacketLink * link = packets->head;
&&&&if (!link)
&&&&&&&&return 0;
&&&&memcpy(packet, &link->packet, sizeof(AVPacket));
&&&&packets->head = link->next;
&&&&packets->size--;
&&&&if (!packets->head)
&&&&&&&&packets->tail = NULL;
&&&&free(link);
&&&&return 1;
static TSMPacketList *
createPacketList()
&&&&TSMPacketList * packets = (TSMPacketList *)malloc(sizeof(TSMPacketList));
&&&&memset(packets, 0, sizeof(TSMPacketList));
&&&&return packets;
static TSMStreamLace *
createStreamLace(unsigned int numStreams)
&&&&unsigned int i;
&&&&TSMStreamLace * lace = (TSMStreamLace *)malloc(sizeof(TSMStreamLace));
&&&&lace->streams = (TSMPacketList **)malloc(sizeof(TSMPacketList *) * numStreams);
&&&&for ( i = 0; i < numStreams; i++)
&&&&&&&&lace->streams[i] = createPacketList();
&&&&lace->numStreams = numStreams;
&&&&return lace;
static void
insertPacket(TSMStreamLace * lace, const AVPacket * packet, double timeStamp)
&&&&fifoPush(lace->streams[packet->stream_index], packet, timeStamp);
static TSMPacketList *
chooseNextStream(TSMStreamLace * lace)
&&&&/* improve lacing so that that audio/video packets that should be
&&&&&&&together do not get stuck into separate segments. */
&&&&TSMPacketList * nextStream = NULL;
&&&&double earliestTimeStamp = DBL_MAX;
&&&&unsigned int i;
&&&&for (i = 0; i < lace->numStreams; i++)
&&&&&&&&TSMPacketList * stream = lace->streams[i];
&&&&&&&&if (stream->size && stream->head->timeStamp < earliestTimeStamp)
&&&&&&&&&&&&nextStream = stream;
&&&&&&&&&&&&earliestTimeStamp = stream->head->timeStamp;
&&&&return nextStream;
static int
removePacket(TSMStreamLace * lace, AVPacket * packet)
&&&&TSMPacketList * stream = chooseNextStream(lace);
&&&&if (!stream)
&&&&&&&&return 0;
&&&&return fifoPop(stream, packet);
static unsigned int
countPackets(const TSMStreamLace * lace)
&&&&unsigned int numPackets = 0;
&&&&unsigned int i;
&&&&for ( i = 0; i < lace->numStreams; i++)
&&&&&&&&const TSMPacketList * stream = lace->streams[i];
&&&&&&&&numPackets += stream->size;
&&&&return numPackets;
static void
removeAllPackets(TSMStreamLace * lace)
&&&&unsigned int i;
&&&&AVPacket packet;
&&&&for ( i = 0; i < lace->numStreams; i++)
&&&&&&&&TSMPacketList * stream = lace->streams[i];
&&&&&&&&while (stream->size)
&&&&&&&&&&&&fifoPop(stream, &packet);
&&&&&&&&&&&&av_free_packet(&packet);
static int
loglevel(const char* arg)
&&&&const struct { const char *name; int level; } log_levels[] = {
&&&&&&&&{ "quiet" , AV_LOG_QUIET },
&&&&&&&&{ "panic" , AV_LOG_PANIC },
&&&&&&&&{ "fatal" , AV_LOG_FATAL },
&&&&&&&&{ "error" , AV_LOG_ERROR },
&&&&&&&&{ "warning", AV_LOG_WARNING },
&&&&&&&&{ "info" , AV_LOG_INFO },
&&&&&&&&{ "verbose", AV_LOG_VERBOSE },
&&&&&&&&{ "debug" , AV_LOG_DEBUG },
&&&&int i;
&&&&for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
&&&&&&&&if (!strcmp(log_levels[i].name, arg)) {
&&&&&&&&&&&&av_log_set_level(log_levels[i].level);
&&&&&&&&&&&&return 0;
&&&&return 1;
//----------------------------------------------------------------
static void usage3(char ** argv, const char * message, const char * details)
&&&&if (message)
&&&&&&&&fprintf(stderr, "ERROR: %s%s\n\n", message, details);
&&&&fprintf(stderr,
&&&&&&&&&&&&"USAGE: %s "
&&&&&&&&&&&&"-i input-MPEG-TS-file "
&&&&&&&&&&&&"-d seconds-per-segment "
&&&&&&&&&&&&"[-o segment-file-prefix] "
&&&&&&&&&&&&"-x output-playlist-m3u8 "
&&&&&&&&&&&&"[-p http-prefix] "
&&&&&&&&&&&&"[-w max-live-segments] "
&&&&&&&&&&&&"[-P pid-file] "
&&&&&&&&&&&&"[--watch-for-kill-file] "
&&&&&&&&&&&&"[--strict-segment-duration] "
&&&&&&&&&&&&"[--avformat-option opt value] "
&&&&&&&&&&&&"[--loglevel level] "
&&&&&&&&&&&&"\n\n",
&&&&&&&&&&&&argv[0]);
&&&&fprintf(stderr,
&&&&&&&&&&&&"Compiled by Daniel Espendiller - www.espend.de\n"
&&&&&&&&&&&&"build on %s %s with %s\n\n"
&&&&&&&&&&&&"Took some code from:\n"
&&&&&&&&&&&&" - source:/svn/legend/segmenter/\n"
&&&&&&&&&&&&" - iStreamdev:http://projects.vdr-developer.org/git/?p=istreamdev.a=f=hb=HEAD\n"
&&&&&&&&&&&&" - live_segmenter:/carsonmcdonald/HTTP-Live-Video-Stream-Segmenter-and-Distributor\n",
&&&&&&&&&&&&__DATE__,
&&&&&&&&&&&&__TIME__,
&&&&&&&&&&&&__VERSION__);
&&&&exit(1);
//----------------------------------------------------------------
static void usage(char ** argv, const char * message)
{ usage3(argv, message, ""); }
//----------------------------------------------------------------
// main_utf8
int main_utf8(int argc, char **argv)
&&&&double target_segment_duration = 0.0;
&&&&char *segment_duration_check = NULL;
&&&&const char *playlist_filename = NULL;
&&&&const char *http_prefix = "";
&&&&long max_tsfiles = 0;
&&&&char *max_tsfiles_check = NULL;
&&&&double prev_segment_time = 0.0;
&&&&double segment_duration = 0.0;
&&&&unsigned int output_index = 0;
&&&&const AVClass *fc = avformat_get_class();
&&&&AVDictionary *format_opts = NULL;
&&&&AVOutputFormat *ofmt = NULL;
&&&&AVFormatContext *ic = NULL;
&&&&AVFormatContext *oc = NULL;
&&&&AVStream *video_st = NULL;
&&&&AVStream *audio_st = NULL;
&&&&AVCodec *codec = NULL;
&&&&char *pid_filename = NULL;
&&&&int video_index = -1;
&&&&int audio_index = -1;
&&&&int kill_file = 0;
&&&&int decode_done = 0;
&&&&int ret = 0;
&&&&int i = 0;
&&&&TSMStreamLace * streamLace = NULL;
&&&&TSMPlaylist * playlist = NULL;
&&&&const double segment_duration_error_tolerance = 0.05;
&&&&double extra_duration_needed = 0;
&&&&int strict_segment_duration = 0;
&&&&av_log_set_level(AV_LOG_INFO);
&&&&for (i = 1; i < argc; i++)
&&&&&&&&if (strcmp(argv[i], "-i") == 0)
&&&&&&&&&&&&if ((argc - i) <= 1)
&&&&&&&&&&&&&&&&usage(argv, "could not parse -i parameter");
&&&&&&&&&&&&i++;
&&&&&&&&&&&&strcpy(input_args.input, argv[i]);
&&&&&&&&else if (strcmp(argv[i], "-o") == 0)
&&&&&&&&&&&&if ((argc - i) <= 1)
&&&&&&&&&&&&&&&&usage(argv, "could not parse -i parameter");
&&&&&&&&&&&&i++;
&&&&&&&&&&&&strcpy(input_args.output_prefix, argv[i]);
&&&&&&&&else if (strcmp(argv[i], "-d") == 0)
&&&&&&&&&&&&if ((argc - i) <= 1) usage(argv, "could not parse -d parameter");
&&&&&&&&&&&&&&&&i++;
&&&&&&&&&&&&
&&&&&&&&&&&&target_segment_duration = strtod(argv[i], &segment_duration_check);
&&&&&&&&&&&&if (segment_duration_check == argv[i] ||
&&&&&&&&&&&&target_segment_duration == HUGE_VAL ||
&&&&&&&&&&&&target_segment_duration == -HUGE_VAL)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&usage3(argv, "invalid segment duration: ", argv[i]);
&&&&&&&&&&&&}
&&&&&&&&else if (strcmp(argv[i], "-x") == 0)
&&&&&&&&&&&&if ((argc - i) <= 1) usage(argv, "could not parse -x parameter");
&&&&&&&&&&&&i++;
&&&&&&&&&&&&playlist_filename = argv[i];
&&&&&&&&else if (strcmp(argv[i], "-p") == 0)
&&&&&&&&&&&&if ((argc - i) <= 1) usage(argv, "could not parse -p parameter");
&&&&&&&&&&&&&&&&i++;
&&&&&&&&&&&&http_prefix = argv[i];
&&&&&&&&else if (strcmp(argv[i], "-w") == 0)
&&&&&&&&&&&&if ((argc - i) <= 1) usage(argv, "could not parse -w parameter");
&&&&&&&&&&&&&&&&i++;
&&&&&&&&&&&&max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10);
&&&&&&&&&&&&if (max_tsfiles_check == argv[i] ||
&&&&&&&&&&&&&&&&max_tsfiles < 0 ||
&&&&&&&&&&&&&&&&max_tsfiles >= INT_MAX)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&usage3(argv, "invalid live stream max window size: ", argv[i]);
&&&&&&&&&&&&}
&&&&if (!input_args.input)
&&&&&&&&usage(argv, "-i input file parameter must be specified");
&&&&printf("+++input_file: %s\n", input_args.input);
&&&&if (!playlist_filename)
&&&&&&&&usage(argv, "-x m3u8 playlist file parameter must be specified");
&&&&printf("+++playlist_filename: %s\n", playlist_filename);
&&&&if (target_segment_duration == 0.0)
&&&&&&&&usage(argv, "-d segment duration parameter must be specified");
&&&&printf("+++target_segment_duration: %f\n", target_segment_duration);
&&&&av_register_all();
&&&&avformat_network_init();
&&&&if (!strcmp(input_args.input, "-")) {
&&&&&&&&strcpy(input_args.input, "pipe:");
&&&&playlist = createPlaylist(max_tsfiles,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&target_segment_duration,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&http_prefix);
&&&&if (!playlist)
&&&&&&&&fprintf(stderr, "Could not allocate space for m3u8 playlist structure\n");
&&&&&&&&goto error;
&&&&ic = avformat_alloc_context();
&&&&ret = avformat_open_input(&ic, input_args.input, NULL, NULL);
&&&&if (ret != 0) {
&&&&&&&&fprintf(stderr, "Could not open input file, make sure it is an mpegts or mp4 file: %d\n", ret);
&&&&&&&&goto error;
&&&&if (avformat_find_stream_info(ic, NULL) < 0) {
&&&&&&&&fprintf(stderr, "Could not read stream information\n");
&&&&&&&&goto error;
&&&&av_dump_format(ic, 0, input_args.input, 0);
&&&&ofmt = av_guess_format("mpegts", NULL, NULL);
&&&&if (!ofmt) {
&&&&&&&&fprintf(stderr, "Could not find MPEG-TS muxer\n");
&&&&&&&&goto error;
&&&&oc = avformat_alloc_context();
&&&&if (!oc) {
&&&&&&&&fprintf(stderr, "Could not allocated output context\n");
&&&&&&&&goto error;
&&&&oc->oformat = ofmt;
&&&&video_index = -1;
&&&&audio_index = -1;
&&&&for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
&&&&&&&&switch (ic->streams[i]->codec->codec_type) {
&&&&&&&&case AVMEDIA_TYPE_VIDEO:
&&&&&&&&&&&&video_index = i;
&&&&&&&&&&&&ic->streams[i]->discard = AVDISCARD_NONE;
&&&&&&&&&&&&video_st = add_output_stream(oc, ic->streams[i]);
&&&&&&&&break;
&&&&&&&&case AVMEDIA_TYPE_AUDIO:
&&&&&&&&&&&&audio_index = i;
&&&&&&&&&&&&ic->streams[i]->discard = AVDISCARD_NONE;
&&&&&&&&&&&&audio_st = add_output_stream(oc, ic->streams[i]);
&&&&&&&&break;
&&&&&&&&default:
&&&&&&&&&&&&ic->streams[i]->discard = AVDISCARD_ALL;
&&&&&&&&break;
&&&&av_dump_format(oc, 0, input_args.output_prefix, 1);
&&&&if (video_index >=0) {
&&&&&&&&codec = avcodec_find_decoder(video_st->codec->codec_id);
&&&&&&&&if (!codec) {
&&&&&&&&&&&&fprintf(stderr, "Could not find video decoder, key frames will not be honored\n");
&&&&&&&&if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
&&&&&&&&&&&&fprintf(stderr, "Could not open video decoder, key frames will not be honored\n");
&&&&sprintf(input_args.output, "%s-%u.ts", input_args.output_prefix, ++output_index);
&&&&if (avio_open(&oc->pb, input_args.output, AVIO_FLAG_WRITE) < 0) {
&&&&&&&&fprintf(stderr, "Could not open '%s'\n", input_args.output);
&&&&&&&&goto error;
&&&&if (avformat_write_header(oc, NULL)) {
&&&&&&&&fprintf(stderr, "Could not write mpegts header to first output file\n");
&&&&&&&&goto error;
&&&&prev_segment_time = (double)(ic->start_time) / (double)(AV_TIME_BASE);
&&&&streamLace = createStreamLace(ic->nb_streams);
&&&&&&&&double segment_time = 0.0;
&&&&&&&&AVPacket packet;
&&&&&&&&double packetStartTime = 0.0;
&&&&&&&&double packetDuration = 0.0;
&&&&&&&&if (!decode_done)
&&&&&&&&&&&&decode_done = av_read_frame(ic, &packet);
&&&&&&&&&&&&if (!decode_done)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&if (packet.stream_index != video_index &&
&&&&&&&&&&&&&&&&&&&&packet.stream_index != audio_index)
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&av_free_packet(&packet);
&&&&&&&&&&&&&&&&&&&&continue;
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&double timeStamp =
&&&&&&&&&&&&&&&&&&&&(double)(packet.pts) *
&&&&&&&&&&&&&&&&&&&&(double)(ic->streams[packet.stream_index]->time_base.num) /
&&&&&&&&&&&&&&&&&&&&(double)(ic->streams[packet.stream_index]->time_base.den);
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&if (av_dup_packet(&packet) < 0)
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&fprintf(stderr, "Could not duplicate packet\n");
&&&&&&&&&&&&&&&&&&&&av_free_packet(&packet);
&&&&&&&&&&&&&&&&&&&&break;
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&insertPacket(streamLace, &packet, timeStamp);
&&&&&&&&&&&&}
&&&&&&&&if (countPackets(streamLace) < 50 && !decode_done)
&&&&&&&&&&&&/* allow the queue to fill up so that the packets can be sorted properly */
&&&&&&&&&&&&continue;
&&&&&&&&if (!removePacket(streamLace, &packet))
&&&&&&&&&&&&if (decode_done)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&/* the queue is empty, we are done */
&&&&&&&&&&&&&&&&break;
&&&&&&&&&&&&}
&&&&&&&&&&&&
&&&&&&&&&&&&assert(decode_done);
&&&&&&&&&&&&continue;
&&&&&&&&packetStartTime =
&&&&&&&&&&&&(double)(packet.pts) *
&&&&&&&&&&&&(double)(ic->streams[packet.stream_index]->time_base.num) /
&&&&&&&&&&&&(double)(ic->streams[packet.stream_index]->time_base.den);
&&&&&&&&packetDuration =
&&&&&&&&&&&&(double)(packet.duration) *
&&&&&&&&&&&&(double)(ic->streams[packet.stream_index]->time_base.num) /
&&&&&&&&&&&&(double)(ic->streams[packet.stream_index]->time_base.den);
#if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG))
&&&&&&&&if (av_log_get_level() >= AV_LOG_VERBOSE)
&&&&&&&&&&&&fprintf(stderr,
&&&&&&&&&&&&&&&&&&&&"stream %i, packet [%f, %f)\n",
&&&&&&&&&&&&&&&&&&&&packet.stream_index,
&&&&&&&&&&&&&&&&&&&&packetStartTime,
&&&&&&&&&&&&&&&&&&&&packetStartTime + packetDuration);
&&&&&&&&segment_duration = packetStartTime + packetDuration - prev_segment_time;
&&&&&&&&// NOTE: segments are supposed to start on a keyframe.
&&&&&&&&// If the keyframe interval and segment duration do not match
&&&&&&&&// forcing the segment creation for "better seeking behavior"
&&&&&&&&// will result in decoding artifacts after seeking or stream switching.
&&&&&&&&if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration)) {
&&&&&&&&&&&&segment_time = packetStartTime;
&&&&&&&&else if (video_index < 0) {
&&&&&&&&&&&&segment_time = packetStartTime;
&&&&&&&&else {
&&&&&&&&&&&&segment_time = prev_segment_time;
&&&&printf("segment time: %f\n", segment_time);
&&&&&&&&if (segment_time - prev_segment_time + segment_duration_error_tolerance >
&&&&&&&&&&&&target_segment_duration + extra_duration_needed)
&&&&&&&&&&&&avio_flush(oc->pb);
&&&&&&&&&&&&avio_close(oc->pb);
&&&&&&&&&&&&// Keep track of accumulated rounding error to account for it in later chunks.
&&&&&&&&&&&&double segment_duration = segment_time - prev_segment_time;
&&&&&&&&&&&&int rounded_segment_duration = (int)(segment_duration + 0.5);
&&&&&&&&&&&&extra_duration_needed += (double)rounded_segment_duration - segment_duration;
&&&&&&&&&&&&updatePlaylist(playlist,
&&&&&&&&&&&&&&&&&&&&&&&&&&&playlist_filename,
&&&&&&&&&&&&&&&&&&&&&&&&&&&input_args.output,
&&&&&&&&&&&&&&&&&&&&&&&&&&&output_index,
&&&&&&&&&&&&&&&&&&&&&&&&&&&rounded_segment_duration);
&&&&&&&&&&&&
&&&&&&&&&&&&sprintf(input_args.output, "%s-%u.ts", input_args.output_prefix, ++output_index);
&&&&&&&&&&&&if (avio_open(&oc->pb, input_args.output, AVIO_FLAG_WRITE) < 0) {
&&&&&&&&&&&&&&&&fprintf(stderr, "Could not open '%s'\n", input_args.output);
&&&&&&&&&&&&&&&&break;
&&&&&&&&&&&&}
&&&&&&&&&&&&// close when we find the 'kill' file
&&&&&&&&&&&&if (kill_file) {
&&&&&&&&&&&&&&&&FILE* fp = fopen("kill", "rb");
&&&&&&&&&&&&&&&&if (fp) {
&&&&&&&&&&&&&&&&&&&&fprintf(stderr, "user abort: found kill file\n");
&&&&&&&&&&&&&&&&&&&&fclose(fp);
&&&&&&&&&&&&&&&&&&&&remove("kill");
&&&&&&&&&&&&&&&&&&&&decode_done = 1;
&&&&&&&&&&&&&&&&&&&&removeAllPackets(streamLace);
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
&&&&&&&&&&&&prev_segment_time = segment_time;
&&&&&&&&ret = av_interleaved_write_frame(oc, &packet);
&&&&&&&&if (ret < 0) {
&&&&&&&&&&&&fprintf(stderr, "Warning: Could not write frame of stream\n");
&&&&&&&&else if (ret > 0) {
&&&&&&&&&&&&fprintf(stderr, "End of stream requested\n");
&&&&&&&&&&&&av_free_packet(&packet);
&&&&&&&&&&&&break;
&&&&&&&&av_free_packet(&packet);
&&&&} while (!decode_done || countPackets(streamLace) > 0);
&&&&av_write_trailer(oc);
&&&&if (video_index >= 0) {
&&&&&&avcodec_close(video_st->codec);
&&&&for(i = 0; i < oc->nb_streams; i++) {
&&&&&&&&av_freep(&oc->streams[i]->codec);
&&&&&&&&av_freep(&oc->streams[i]);
&&&&avio_close(oc->pb);
&&&&av_free(oc);
&&&&updatePlaylist(playlist,
&&&&&&&&&&&&&&&&&&&playlist_filename,
&&&&&&&&&&&&&&&&&&&input_args.output,
&&&&&&&&&&&&&&&&&&&output_index,
&&&&&&&&&&&&&&&&&&&segment_duration);
&&&&closePlaylist(playlist);
&&&&releasePlaylist(&playlist);
&&&&if (pid_filename)
&&&&&&&&remove(pid_filename);
&&&&return 0;
&&&&if (pid_filename)
&&&&&&&&remove(pid_filename);
&&&&return 1;
int main(int argc, char ** argv)
&&&&return main_utf8(argc, argv);
四、 准备webserver, 建议用lighttpd。
下载最新的lighttpd-1.4.32,
./configure –prefix=dir
Make && make install
下面就是配置了:
server.modules必须启用:
mod_access
在mimetype.assign当中加入:
".m3u8" & & & & => & & &"application/x-mpegURL",&
".ts" & & & & & => & & &"video/MP2T",
server.document-root 设置为你的目录,记住设置下面:
index-file.names & & & & & &= ( "index.php", "index.html",
& & & & & & & & & & & & & & & & "index.htm", "default.htm",
& & & & & & & & & & & & & & & & "index.lighttpd.html")
打开http://IP:port时发现出现404 not foud,这说明你的server已经成功启动,你要做的就是把/var/www/ index.lighttpd.html 拷贝到你的目录下,你就可以打开这个html了。
五、 设置好网络以后,将index.m3u8和相关文件按照自定义顺序拷贝到server的目录下,然后就可以开始试验了。
六、 打开IOS,在movie player当中输入http://iP/index.m3u8,播放即可,非常流畅。
阅读(432) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 linux下搭建测试环境 的文章

 

随机推荐