一、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支持1920x1080p,audio和video解码器都是IOS硬件加速当中提供的,因而不需要你对bitrate、schannel、bitrate等进行转换。
ffmpeg -i ~/Videos/1.ts -f mpegts -acodec libmp3lame -ar 48000 -ab 64k -s 1080x720 -vcodec libx264 sample.ts
获取到符合的码流以后,需要对码流进行segment。
三、Segment
Ios规定的支持http streaming的方式是由一个索引文件(后缀为.m3u8)和相关分段文件决定的,其中m3u8当中的内容如下:
#EXTM3U
#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 -o -d -x -p
分配好以后发现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;
- }
- else
- {
- 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;
- }
- else
- {
- 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);
- }
- else
- {
- /* 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;
- }
- else
- {
- /* 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;
- }
- //----------------------------------------------------------------
- // usage3
- //
- 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:http://svn.assembla.com/svn/legend/segmenter/\n"
- " - iStreamdev:http://projects.vdr-developer.org/git/?p=istreamdev.git;a=tree;f=segmenter;hb=HEAD\n"
- " - live_segmenter:http://github.com/carsonmcdonald/HTTP-Live-Video-Stream-Segmenter-and-Distributor\n",
- __DATE__,
- __TIME__,
- __VERSION__);
-
- exit(1);
- }
- //----------------------------------------------------------------
- // usage
- //
- 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);
-
- do {
- 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);
- #endif
- 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;
- error:
- 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,播放即可,非常流畅。