国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
詳解FFMPEG API
轉(zhuǎn)自:http://3xin2yi.info/wwwroot/tech/doku.php/tech:multimedia:ffmpeg
認(rèn)識(shí)FFmpeg
FFMPEG堪稱自由軟件中最完備的一套多媒體支持庫(kù),它幾乎實(shí)現(xiàn)了所有當(dāng)下常見的數(shù)據(jù)封裝格式、多媒體傳輸協(xié)議以及音視頻編解碼器。因此,對(duì)于從事多媒體技術(shù)開發(fā)的工程師來說,深入研究FFMPEG成為一門必不可少的工作,可以這樣說,F(xiàn)FMPEG之于多媒體開發(fā)工程師的重要性正如kernel之于嵌入式系統(tǒng)工程師一般。
幾個(gè)小知識(shí):
FFMPEG項(xiàng)目是由法國(guó)人Fabrice Bellard發(fā)起的,此人也是著名的CPU模擬器項(xiàng)目QEMU的發(fā)起者,同時(shí)還是圓周率算法紀(jì)錄的保持者。
FF是Fast Forward的意思,翻譯成中文是“快進(jìn)”。
FFMPEG的LOGO是一個(gè)”Z字掃描”示意圖,Z字掃描用于將圖像的二維頻域數(shù)據(jù)一維化,同時(shí)保證了一維化的數(shù)據(jù)具備良好的統(tǒng)計(jì)特性,從而提高其后要進(jìn)行的一維熵編碼的效率。
關(guān)于恥辱柱(Hall of Shame):FFMpeg大部分代碼遵循LGPL許可證,如果使用者對(duì)FFMpeg進(jìn)行了修改,要求公布修改的源代碼;有少部分代碼遵循GPL許可證,要求使用者同時(shí)公開使用FFMpeg的軟件的源代碼。實(shí)際上,除去部分大的系統(tǒng)軟件開發(fā)商(Microsoft、Apple等)以及某些著名的音視頻服務(wù)提供商(Divx、Real等)提供的自有播放器之外,絕大部分第三方開發(fā)的播放器都離不開FFMpeg的支持,像Linux桌面環(huán)境中的開源播放器VLC、MPlayer,Windows下的KMPlayer、暴風(fēng)影音以及Android下幾乎全部第三方播放器都是基于FFMpeg的。也有許多看似具備自主技術(shù)的播放器,其實(shí)也都不聲不響地使用了FFMpeg,這種行為被稱為“盜竊”,參與“盜竊”的公司的名字則被刻在恥辱柱上,國(guó)產(chǎn)播放器暴風(fēng)影音、QQ影音于2009年上榜。
示例程序
[html] view plaincopy
<span style="font-size:18px;">解碼:</span>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include "libavutil/avstring.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libavutil/opt.h"
#include "libswscale/swscale.h"
#define DECODED_AUDIO_BUFFER_SIZE            192000
struct options
{
int streamId;
int frames;
int nodec;
int bplay;
int thread_count;
int64_t lstart;
char finput[256];
char foutput1[256];
char foutput2[256];
};
int parse_options(struct options *opts, int argc, char** argv)
{
int optidx;
char *optstr;
if (argc < 2) return -1;
opts->streamId = -1;
opts->lstart = -1;
opts->frames = -1;
opts->foutput1[0] = 0;
opts->foutput2[0] = 0;
opts->nodec = 0;
opts->bplay = 0;
opts->thread_count = 0;
strcpy(opts->finput, argv[1]);
optidx = 2;
while (optidx < argc)
{
optstr = argv[optidx++];
if (*optstr++ != '-') return -1;
switch (*optstr++)
{
case 's':  //< stream id
opts->streamId = atoi(optstr);
break;
case 'f':  //< frames
opts->frames = atoi(optstr);
break;
case 'k':  //< skipped
opts->lstart = atoll(optstr);
break;
case 'o':  //< output
strcpy(opts->foutput1, optstr);
strcat(opts->foutput1, ".mpg");
strcpy(opts->foutput2, optstr);
strcat(opts->foutput2, ".raw");
break;
case 'n': //decoding and output options
if (strcmp("dec", optstr) == 0)
opts->nodec = 1;
break;
case 'p':
opts->bplay = 1;
break;
case 't':
opts->thread_count = atoi(optstr);
break;
default:
return -1;
}
}
return 0;
}
void show_help(char* program)
{
printf("Simple FFMPEG test program\n");
printf("Usage: %s inputfile [-sstreamid [-fframes] [-kskipped] [-ooutput_filename(without extension)] [-ndec] [-p] [-tthread_count]]\n",
program);
return;
}
static void log_callback(void* ptr, int level, const char* fmt, va_list vl)
{
vfprintf(stdout, fmt, vl);
}
/*
* audio renderer code (oss)
*/
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#define OSS_DEVICE "/dev/dsp0"
struct audio_dsp
{
int audio_fd;
int channels;
int format;
int speed;
};
int map_formats(enum AVSampleFormat format)
{
switch(format)
{
case AV_SAMPLE_FMT_U8:
return AFMT_U8;
case AV_SAMPLE_FMT_S16:
return AFMT_S16_LE;
default:
return AFMT_U8;
}
}
int set_audio(struct audio_dsp* dsp)
{
if (dsp->audio_fd == -1)
{
printf("Invalid audio dsp id!\n");
return -1;
}
if (-1 == ioctl(dsp->audio_fd, SNDCTL_DSP_SETFMT, &dsp->format))
{
printf("Failed to set dsp format!\n");
return -1;
}
if (-1 == ioctl(dsp->audio_fd, SNDCTL_DSP_CHANNELS, &dsp->channels))
{
printf("Failed to set dsp format!\n");
return -1;
}
if (-1 == ioctl(dsp->audio_fd, SNDCTL_DSP_SPEED, &dsp->speed))
{
printf("Failed to set dsp format!\n");
return -1;
}
return 0;
}
int play_pcm(struct audio_dsp* dsp, unsigned char *buf, int size)
{
if (dsp->audio_fd == -1)
{
printf("Invalid audio dsp id!\n");
return -1;
}
if (-1 == write(dsp->audio_fd, buf, size))
{
printf("Failed to write audio dsp!\n");
return -1;
}
return 0;
}
/* audio renderer code end */
/* video renderer code*/
#include <linux/fb.h>
#include <sys/mman.h>
#define FB_DEVICE "/dev/fb0"
enum pic_format
{
eYUV_420_Planer,
};
struct video_fb
{
int video_fd;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
unsigned char *fbp;
AVFrame *frameRGB;
struct
{
int x;
int y;
} video_pos;
};
int open_video(struct video_fb *fb, int x, int y)
{
int screensize;
fb->video_fd = open(FB_DEVICE, O_WRONLY);
if (fb->video_fd == -1) return -1;
if (ioctl(fb->video_fd, FBIOGET_FSCREENINFO, &fb->finfo)) return -2;
if (ioctl(fb->video_fd, FBIOGET_VSCREENINFO, &fb->vinfo)) return -2;
printf("video device: resolution %dx%d, %dbpp\n", fb->vinfo.xres, fb->vinfo.yres, fb->vinfo.bits_per_pixel);
screensize = fb->vinfo.xres * fb->vinfo.yres * fb->vinfo.bits_per_pixel / 8;
fb->fbp = (unsigned char *) mmap(0, screensize, PROT_READ|PROT_WRITE, MAP_SHARED, fb->video_fd, 0);
if (fb->fbp == -1) return -3;
if (x >= fb->vinfo.xres || y >= fb->vinfo.yres)
{
return -4;
}
else
{
fb->video_pos.x = x;
fb->video_pos.y = y;
}
fb->frameRGB = avcodec_alloc_frame();
if (!fb->frameRGB) return -5;
return 0;
}
/* only 420P supported now */
int show_picture(struct video_fb *fb, AVFrame *frame, int width, int height, enum pic_format format)
{
struct SwsContext *sws;
int i;
unsigned char *dest;
unsigned char *src;
if (fb->video_fd == -1) return -1;
if ((fb->video_pos.x >= fb->vinfo.xres) || (fb->video_pos.y >= fb->vinfo.yres)) return -2;
if (fb->video_pos.x + width > fb->vinfo.xres)
{
width = fb->vinfo.xres - fb->video_pos.x;
}
if (fb->video_pos.y + height > fb->vinfo.yres)
{
height = fb->vinfo.yres - fb->video_pos.y;
}
if (format == PIX_FMT_YUV420P)
{
sws = sws_getContext(width, height, format, width, height, PIX_FMT_RGB32, SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (sws == 0)
{
return -3;
}
if (sws_scale(sws, frame->data, frame->linesize, 0, height, fb->frameRGB->data, fb->frameRGB->linesize))
{
return -3;
}
dest = fb->fbp + (fb->video_pos.x+fb->vinfo.xoffset) * (fb->vinfo.bits_per_pixel/8) +(fb->video_pos.y+fb->vinfo.yoffset) * fb->finfo.line_length;
for (i = 0; i < height; i++)
{
memcpy(dest, src, width*4);
src += fb->frameRGB->linesize[0];
dest += fb->finfo.line_length;
}
}
return 0;
}
void close_video(struct video_fb *fb)
{
if (fb->video_fd != -1)
{
munmap(fb->fbp, fb->vinfo.xres * fb->vinfo.yres * fb->vinfo.bits_per_pixel / 8);
close(fb->video_fd);
fb->video_fd = -1;
}
}
/* video renderer code end */
int main(int argc, char **argv)
{
AVFormatContext* pCtx = 0;
AVCodecContext *pCodecCtx = 0;
AVCodec *pCodec = 0;
AVPacket packet;
AVFrame *pFrame = 0;
FILE *fpo1 = NULL;
FILE *fpo2 = NULL;
int nframe;
int err;
int got_picture;
int picwidth, picheight, linesize;
unsigned char *pBuf;
int i;
int64_t timestamp;
struct options opt;
int usefo = 0;
struct audio_dsp dsp;
struct video_fb fb;
int dusecs;
float usecs1 = 0;
float usecs2 = 0;
struct timeval elapsed1, elapsed2;
int decoded = 0;
av_register_all();
av_log_set_callback(log_callback);
av_log_set_level(50);
if (parse_options(&opt, argc, argv) < 0 || (strlen(opt.finput) == 0))
{
show_help(argv[0]);
return 0;
}
err = avformat_open_input(&pCtx, opt.finput, 0, 0);
if (err < 0)
{
printf("\n->(avformat_open_input)\tERROR:\t%d\n", err);
goto fail;
}
err = avformat_find_stream_info(pCtx, 0);
if (err < 0)
{
printf("\n->(avformat_find_stream_info)\tERROR:\t%d\n", err);
goto fail;
}
if (opt.streamId < 0)
{
av_dump_format(pCtx, 0, pCtx->filename, 0);
goto fail;
}
else
{
printf("\n extra data in Stream %d (%dB):", opt.streamId, pCtx->streams[opt.streamId]->codec->extradata_size);
for (i = 0; i < pCtx->streams[opt.streamId]->codec->extradata_size; i++)
{
if (i%16 == 0) printf("\n");
printf("%2x  ", pCtx->streams[opt.streamId]->codec->extradata[i]);
}
}
/* try opening output files */
if (strlen(opt.foutput1) && strlen(opt.foutput2))
{
fpo1 = fopen(opt.foutput1, "wb");
fpo2 = fopen(opt.foutput2, "wb");
if (!fpo1 || !fpo2)
{
printf("\n->error opening output files\n");
goto fail;
}
usefo = 1;
}
else
{
usefo = 0;
}
if (opt.streamId >= pCtx->nb_streams)
{
printf("\n->StreamId\tERROR\n");
goto fail;
}
if (opt.lstart > 0)
{
err = av_seek_frame(pCtx, opt.streamId, opt.lstart, AVSEEK_FLAG_ANY);
if (err < 0)
{
printf("\n->(av_seek_frame)\tERROR:\t%d\n", err);
goto fail;
}
}
/* for decoder configuration */
if (!opt.nodec)
{
/* prepare codec */
pCodecCtx = pCtx->streams[opt.streamId]->codec;
if (opt.thread_count <= 16 && opt.thread_count > 0 )
{
pCodecCtx->thread_count = opt.thread_count;
pCodecCtx->thread_type = FF_THREAD_FRAME;
}
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (!pCodec)
{
printf("\n->can not find codec!\n");
goto fail;
}
err = avcodec_open2(pCodecCtx, pCodec, 0);
if (err < 0)
{
printf("\n->(avcodec_open)\tERROR:\t%d\n", err);
goto fail;
}
pFrame = avcodec_alloc_frame();
/* prepare device */
if (opt.bplay)
{
/* audio devices */
dsp.audio_fd = open(OSS_DEVICE, O_WRONLY);
if (dsp.audio_fd == -1)
{
printf("\n-> can not open audio device\n");
goto fail;
}
dsp.channels = pCodecCtx->channels;
dsp.speed = pCodecCtx->sample_rate;
dsp.format = map_formats(pCodecCtx->sample_fmt);
if (set_audio(&dsp) < 0)
{
printf("\n-> can not set audio device\n");
goto fail;
}
/* video devices */
if (open_video(&fb, 0, 0) != 0)
{
printf("\n-> can not open video device\n");
goto fail;
}
}
}
nframe = 0;
while(nframe < opt.frames || opt.frames == -1)
{
gettimeofday(&elapsed1, NULL);
err = av_read_frame(pCtx, &packet);
if (err < 0)
{
printf("\n->(av_read_frame)\tERROR:\t%d\n", err);
break;
}
gettimeofday(&elapsed2, NULL);
dusecs = (elapsed2.tv_sec - elapsed1.tv_sec)*1000000 + (elapsed2.tv_usec - elapsed1.tv_usec);
usecs2 += dusecs;
timestamp = av_rescale_q(packet.dts, pCtx->streams[packet.stream_index]->time_base, (AVRational){1, AV_TIME_BASE});
printf("\nFrame No %5d stream#%d\tsize %6dB, timestamp:%6lld, dts:%6lld, pts:%6lld, ", nframe++, packet.stream_index, packet.size,
timestamp, packet.dts, packet.pts);
if (packet.stream_index == opt.streamId)
{
#if 0
for (i = 0; i < 16; /*packet.size;*/ i++)
{
if (i%16 == 0) printf("\n pktdata: ");
printf("%2x  ", packet.data[i]);
}
printf("\n");
#endif
if (usefo)
{
fwrite(packet.data, packet.size, 1, fpo1);
fflush(fpo1);
}
if (pCtx->streams[opt.streamId]->codec->codec_type == AVMEDIA_TYPE_VIDEO && !opt.nodec)
{
picheight = pCtx->streams[opt.streamId]->codec->height;
picwidth = pCtx->streams[opt.streamId]->codec->width;
gettimeofday(&elapsed1, NULL);
avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
decoded++;
gettimeofday(&elapsed2, NULL);
dusecs = (elapsed2.tv_sec - elapsed1.tv_sec)*1000000 + (elapsed2.tv_usec - elapsed1.tv_usec);
usecs1 += dusecs;
if (got_picture)
{
printf("[Video: type %d, ref %d, pts %lld, pkt_pts %lld, pkt_dts %lld]",
pFrame->pict_type, pFrame->reference, pFrame->pts, pFrame->pkt_pts, pFrame->pkt_dts);
if (pCtx->streams[opt.streamId]->codec->pix_fmt == PIX_FMT_YUV420P)
{
if (usefo)
{
linesize = pFrame->linesize[0];
pBuf = pFrame->data[0];
for (i = 0; i < picheight; i++)
{
fwrite(pBuf, picwidth, 1, fpo2);
pBuf += linesize;
}
linesize = pFrame->linesize[1];
pBuf = pFrame->data[1];
for (i = 0; i < picheight/2; i++)
{
fwrite(pBuf, picwidth/2, 1, fpo2);
pBuf += linesize;
}
linesize = pFrame->linesize[2];
pBuf = pFrame->data[2];
for (i = 0; i < picheight/2; i++)
{
fwrite(pBuf, picwidth/2, 1, fpo2);
pBuf += linesize;
}
fflush(fpo2);
}
if (opt.bplay)
{
/* show picture */
show_picture(&fb, pFrame, picheight, picwidth, PIX_FMT_YUV420P);
}
}
}
av_free_packet(&packet);
}
else if (pCtx->streams[opt.streamId]->codec->codec_type == AVMEDIA_TYPE_AUDIO && !opt.nodec)
{
int got;
gettimeofday(&elapsed1, NULL);
avcodec_decode_audio4(pCodecCtx, pFrame, &got, &packet);
decoded++;
gettimeofday(&elapsed2, NULL);
dusecs = (elapsed2.tv_sec - elapsed1.tv_sec)*1000000 + (elapsed2.tv_usec - elapsed1.tv_usec);
usecs1 += dusecs;
if (got)
{
printf("[Audio: %5dB raw data, decoding time: %d]", pFrame->linesize[0], dusecs);
if (usefo)
{
fwrite(pFrame->data[0],  pFrame->linesize[0], 1, fpo2);
fflush(fpo2);
}
if (opt.bplay)
{
play_pcm(&dsp, pFrame->data[0],  pFrame->linesize[0]);
}
}
}
}
}
if (!opt.nodec && pCodecCtx)
{
avcodec_close(pCodecCtx);
}
printf("\n%d frames parsed, average %.2f us per frame\n", nframe, usecs2/nframe);
printf("%d frames decoded, average %.2f us per frame\n", decoded, usecs1/decoded);
fail:
if (pCtx)
{
avformat_close_input(&pCtx);
}
if (fpo1)
{
fclose(fpo1);
}
if (fpo2)
{
fclose(fpo2);
}
if (!pFrame)
{
av_free(pFrame);
}
if (!usefo && (dsp.audio_fd != -1))
{
close(dsp.audio_fd);
}
if (!usefo && (fb.video_fd != -1))
{
close_video(&fb);
}
return 0;
}
這一小段代碼可以實(shí)現(xiàn)的功能包括:
打開一個(gè)多媒體文件并獲取基本的媒體信息。
獲取編碼器句柄。
根據(jù)給定的時(shí)間標(biāo)簽進(jìn)行一個(gè)跳轉(zhuǎn)。
讀取數(shù)據(jù)幀。
解碼音頻幀或者視頻幀。
關(guān)閉多媒體文件。
這些功能足以支持一個(gè)功能強(qiáng)大的多媒體播放器,因?yàn)樽顝?fù)雜的解復(fù)用、解碼、數(shù)據(jù)分析過程已經(jīng)在FFMpeg內(nèi)部實(shí)現(xiàn)了,需要關(guān)注的僅剩同步問題。
用戶接口
編解碼器、數(shù)據(jù)幀、媒體流和容器是數(shù)字媒體處理系統(tǒng)的四個(gè)基本概念。
首先需要統(tǒng)一術(shù)語:
容器/文件(Conainer/File):即特定格式的多媒體文件。
媒體流(Stream):指時(shí)間軸上的一段連續(xù)數(shù)據(jù),如一段聲音數(shù)據(jù),一段視頻數(shù)據(jù)或一段字幕數(shù)據(jù),可以是壓縮的,也可以是非壓縮的,壓縮的數(shù)據(jù)需要關(guān)聯(lián)特定的編解碼器。
數(shù)據(jù)幀/數(shù)據(jù)包(Frame/Packet):通常,一個(gè)媒體流由大量的數(shù)據(jù)幀組成,對(duì)于壓縮數(shù)據(jù),幀對(duì)應(yīng)著編解碼器的最小處理單元。通常,分屬于不同媒體流的數(shù)據(jù)幀交錯(cuò)復(fù)用于容器之中,參見交錯(cuò)
編解碼器:編解碼器以幀為單位實(shí)現(xiàn)壓縮數(shù)據(jù)和原始數(shù)據(jù)之間的相互轉(zhuǎn)換。
在FFMPEG中,使用AVFormatContext、AVStream、AVCodecContext、AVCodec及AVPacket等結(jié)構(gòu)來抽象這些基本要素,它們的關(guān)系如下圖所示:
這是一個(gè)描述編解碼器上下文的數(shù)據(jù)結(jié)構(gòu),包含了眾多編解碼器需要的參數(shù)信息,如下列出了部分比較重要的域:
[cpp] view plaincopy
typedef struct AVCodecContext {
......
/**
* some codecs need / can use extradata like Huffman tables.
* mjpeg: Huffman tables
* rv10: additional flags
* mpeg4: global headers (they can be in the bitstream or here)
* The allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger
* than extradata_size to avoid prolems if it is read with the bitstream reader.
* The bytewise contents of extradata must not depend on the architecture or CPU endianness.
* - encoding: Set/allocated/freed by libavcodec.
* - decoding: Set/allocated/freed by user.
*/
uint8_t *extradata;
int extradata_size;
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identically 1.
* - encoding: MUST be set by user.
* - decoding: Set by libavcodec.
*/
AVRational time_base;
/* video only */
/**
* picture width / height.
* - encoding: MUST be set by user.
* - decoding: Set by libavcodec.
* Note: For compatibility it is possible to set this instead of
* coded_width/height before decoding.
*/
int width, height;
......
/* audio only */
int sample_rate; ///< samples per second
int channels;    ///< number of audio channels
/**
* audio sample format
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
enum SampleFormat sample_fmt;  ///< sample format
/* The following data should not be initialized. */
/**
* Samples per packet, initialized when calling 'init'.
*/
int frame_size;
int frame_number;   ///< audio or video frame number
......
char codec_name[32];
enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */
enum CodecID codec_id; /* see CODEC_ID_xxx */
/**
* fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
* This is used to work around some encoder bugs.
* A demuxer should set this to what is stored in the field used to identify the codec.
* If there are multiple such fields in a container then the demuxer should choose the one
* which maximizes the information about the used codec.
* If the codec tag field in a container is larger then 32 bits then the demuxer should
* remap the longer ID to 32 bits with a table or other structure. Alternatively a new
* extra_codec_tag + size could be added but for this a clear advantage must be demonstrated
* first.
* - encoding: Set by user, if not then the default based on codec_id will be used.
* - decoding: Set by user, will be converted to uppercase by libavcodec during init.
*/
unsigned int codec_tag;
......
/**
* Size of the frame reordering buffer in the decoder.
* For MPEG-2 it is 1 IPB or 0 low delay IP.
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
int has_b_frames;
/**
* number of bytes per packet if constant and known or 0
* Used by some WAV based audio codecs.
*/
int block_align;
......
/**
* bits per sample/pixel from the demuxer (needed for huffyuv).
* - encoding: Set by libavcodec.
* - decoding: Set by user.
*/
int bits_per_coded_sample;
......
} AVCodecContext;
如果是單純使用libavcodec,這部分信息需要調(diào)用者進(jìn)行初始化;如果是使用整個(gè)FFMPEG庫(kù),這部分信息在調(diào)用avformat_open_input和avformat_find_stream_info的過程中根據(jù)文件的頭信息及媒體流內(nèi)的頭部信息完成初始化。其中幾個(gè)主要域的釋義如下:
extradata/extradata_size:這個(gè)buffer中存放了解碼器可能會(huì)用到的額外信息,在av_read_frame中填充。一般來說,首先,某種具體格式的demuxer在讀取格式頭信息的時(shí)候會(huì)填充extradata,其次,如果demuxer沒有做這個(gè)事情,比如可能在頭部壓根兒就沒有相關(guān)的編解碼信息,則相應(yīng)的parser會(huì)繼續(xù)從已經(jīng)解復(fù)用出來的媒體流中繼續(xù)尋找。在沒有找到任何額外信息的情況下,這個(gè)buffer指針為空。
time_base:
width/height:視頻的寬和高。
sample_rate/channels:音頻的采樣率和信道數(shù)目。
sample_fmt: 音頻的原始采樣格式。
codec_name/codec_type/codec_id/codec_tag:編解碼器的信息。
該結(jié)構(gòu)體描述一個(gè)媒體流,定義如下:
[cpp] view plaincopy
typedef struct AVStream {
int index;    /**< stream index in AVFormatContext */
int id;       /**< format-specific stream ID */
AVCodecContext *codec; /**< codec context */
/**
* Real base framerate of the stream.
* This is the lowest framerate with which all timestamps can be
* represented accurately (it is the least common multiple of all
* framerates in the stream). Note, this value is just a guess!
* For example, if the time base is 1/90000 and all frames have either
* approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
*/
AVRational r_frame_rate;
......
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* time base should be 1/framerate and timestamp increments should be 1.
*/
AVRational time_base;
......
/**
* Decoding: pts of the first frame of the stream, in stream time base.
* Only set this if you are absolutely 100% sure that the value you set
* it to really is the pts of the first frame.
* This may be undefined (AV_NOPTS_VALUE).
* @note The ASF header does NOT contain a correct start_time the ASF
* demuxer must NOT set this.
*/
int64_t start_time;
/**
* Decoding: duration of the stream, in stream time base.
* If a source file does not specify a duration, but does specify
* a bitrate, this value will be estimated from bitrate and file size.
*/
int64_t duration;
#if LIBAVFORMAT_VERSION_INT < (53<<16)
char language[4]; /** ISO 639-2/B 3-letter language code (empty string if undefined) */
#endif
/* av_read_frame() support */
enum AVStreamParseType need_parsing;
struct AVCodecParserContext *parser;
......
/* av_seek_frame() support */
AVIndexEntry *index_entries; /**< Only used if the format does not
support seeking natively. */
int nb_index_entries;
unsigned int index_entries_allocated_size;
int64_t nb_frames;                 ///< number of frames in this stream if known or 0
......
/**
* Average framerate
*/
AVRational avg_frame_rate;
......
} AVStream;
主要域的釋義如下,其中大部分域的值可以由avformat_open_input根據(jù)文件頭的信息確定,缺少的信息需要通過調(diào)用avformat_find_stream_info讀幀及軟解碼進(jìn)一步獲?。?div style="height:15px;">
index/id:index對(duì)應(yīng)流的索引,這個(gè)數(shù)字是自動(dòng)生成的,根據(jù)index可以從AVFormatContext::streams表中索引到該流;而id則是流的標(biāo)識(shí),依賴于具體的容器格式。比如對(duì)于MPEG TS格式,id就是pid。
time_base:流的時(shí)間基準(zhǔn),是一個(gè)實(shí)數(shù),該流中媒體數(shù)據(jù)的pts和dts都將以這個(gè)時(shí)間基準(zhǔn)為粒度。通常,使用av_rescale/av_rescale_q可以實(shí)現(xiàn)不同時(shí)間基準(zhǔn)的轉(zhuǎn)換。
start_time:流的起始時(shí)間,以流的時(shí)間基準(zhǔn)為單位,通常是該流中第一個(gè)幀的pts。
duration:流的總時(shí)間,以流的時(shí)間基準(zhǔn)為單位。
need_parsing:對(duì)該流parsing過程的控制域。
nb_frames:流內(nèi)的幀數(shù)目。
r_frame_rate/framerate/avg_frame_rate:幀率相關(guān)。
codec:指向該流對(duì)應(yīng)的AVCodecContext結(jié)構(gòu),調(diào)用avformat_open_input時(shí)生成。
parser:指向該流對(duì)應(yīng)的AVCodecParserContext結(jié)構(gòu),調(diào)用avformat_find_stream_info時(shí)生成。。
這個(gè)結(jié)構(gòu)體描述了一個(gè)媒體文件或媒體流的構(gòu)成和基本信息,定義如下:
[cpp] view plaincopy
typedef struct AVFormatContext {
const AVClass *av_class; /**< Set by avformat_alloc_context. */
/* Can only be iformat or oformat, not both at the same time. */
struct AVInputFormat *iformat;
struct AVOutputFormat *oformat;
void *priv_data;
ByteIOContext *pb;
unsigned int nb_streams;
AVStream *streams[MAX_STREAMS];
char filename[1024]; /**< input or output filename */
/* stream info */
int64_t timestamp;
#if LIBAVFORMAT_VERSION_INT < (53<<16)
char title[512];
char author[512];
char copyright[512];
char comment[512];
char album[512];
int year;  /**< ID3 year, 0 if none */
int track; /**< track number, 0 if none */
char genre[32]; /**< ID3 genre */
#endif
int ctx_flags; /**< Format-specific flags, see AVFMTCTX_xx */
/* private data for pts handling (do not modify directly). */
/** This buffer is only needed when packets were already buffered but
not decoded, for example to get the codec parameters in MPEG
streams. */
struct AVPacketList *packet_buffer;
/** Decoding: position of the first frame of the component, in
AV_TIME_BASE fractional seconds. NEVER set this value directly:
It is deduced from the AVStream values.  */
int64_t start_time;
/** Decoding: duration of the stream, in AV_TIME_BASE fractional
seconds. Only set this value if you know none of the individual stream
durations and also dont set any of them. This is deduced from the
AVStream values if not set.  */
int64_t duration;
/** decoding: total file size, 0 if unknown */
int64_t file_size;
/** Decoding: total stream bitrate in bit/s, 0 if not
available. Never set it directly if the file_size and the
duration are known as FFmpeg can compute it automatically. */
int bit_rate;
/* av_read_frame() support */
AVStream *cur_st;
#if LIBAVFORMAT_VERSION_INT < (53<<16)
const uint8_t *cur_ptr_deprecated;
int cur_len_deprecated;
AVPacket cur_pkt_deprecated;
#endif
/* av_seek_frame() support */
int64_t data_offset; /** offset of the first packet */
int index_built;
int mux_rate;
unsigned int packet_size;
int preload;
int max_delay;
#define AVFMT_NOOUTPUTLOOP -1
#define AVFMT_INFINITEOUTPUTLOOP 0
/** number of times to loop output in formats that support it */
int loop_output;
int flags;
#define AVFMT_FLAG_GENPTS       0x0001 ///< Generate missing pts even if it requires parsing future frames.
#define AVFMT_FLAG_IGNIDX       0x0002 ///< Ignore index.
#define AVFMT_FLAG_NONBLOCK     0x0004 ///< Do not block when reading packets from input.
#define AVFMT_FLAG_IGNDTS       0x0008 ///< Ignore DTS on frames that contain both DTS & PTS
#define AVFMT_FLAG_NOFILLIN     0x0010 ///< Do not infer any values from other values, just return what is stored in the container
#define AVFMT_FLAG_NOPARSE      0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled
#define AVFMT_FLAG_RTP_HINT     0x0040 ///< Add RTP hinting to the output file
int loop_input;
/** decoding: size of data to probe; encoding: unused. */
unsigned int probesize;
/**
* Maximum time (in AV_TIME_BASE units) during which the input should
* be analyzed in avformat_find_stream_info().
*/
int max_analyze_duration;
const uint8_t *key;
int keylen;
unsigned int nb_programs;
AVProgram **programs;
/**
* Forced video codec_id.
* Demuxing: Set by user.
*/
enum CodecID video_codec_id;
/**
* Forced audio codec_id.
* Demuxing: Set by user.
*/
enum CodecID audio_codec_id;
/**
* Forced subtitle codec_id.
* Demuxing: Set by user.
*/
enum CodecID subtitle_codec_id;
/**
* Maximum amount of memory in bytes to use for the index of each stream.
* If the index exceeds this size, entries will be discarded as
* needed to maintain a smaller size. This can lead to slower or less
* accurate seeking (depends on demuxer).
* Demuxers for which a full in-memory index is mandatory will ignore
* this.
* muxing  : unused
* demuxing: set by user
*/
unsigned int max_index_size;
/**
* Maximum amount of memory in bytes to use for buffering frames
* obtained from realtime capture devices.
*/
unsigned int max_picture_buffer;
unsigned int nb_chapters;
AVChapter **chapters;
/**
* Flags to enable debugging.
*/
int debug;
#define FF_FDEBUG_TS        0x0001
/**
* Raw packets from the demuxer, prior to parsing and decoding.
* This buffer is used for buffering packets until the codec can
* be identified, as parsing cannot be done without knowing the
* codec.
*/
struct AVPacketList *raw_packet_buffer;
struct AVPacketList *raw_packet_buffer_end;
struct AVPacketList *packet_buffer_end;
AVMetadata *metadata;
/**
* Remaining size available for raw_packet_buffer, in bytes.
* NOT PART OF PUBLIC API
*/
#define RAW_PACKET_BUFFER_SIZE 2500000
int raw_packet_buffer_remaining_size;
/**
* Start time of the stream in real world time, in microseconds
* since the unix epoch (00:00 1st January 1970). That is, pts=0
* in the stream was captured at this real world time.
* - encoding: Set by user.
* - decoding: Unused.
*/
int64_t start_time_realtime;
} AVFormatContext;
這是FFMpeg中最為基本的一個(gè)結(jié)構(gòu),是其他所有結(jié)構(gòu)的根,是一個(gè)多媒體文件或流的根本抽象。其中:
nb_streams和streams所表示的AVStream結(jié)構(gòu)指針數(shù)組包含了所有內(nèi)嵌媒體流的描述;
iformat和oformat指向?qū)?yīng)的demuxer和muxer指針;
pb則指向一個(gè)控制底層數(shù)據(jù)讀寫的ByteIOContext結(jié)構(gòu)。
start_time和duration是從streams數(shù)組的各個(gè)AVStream中推斷出的多媒體文件的起始時(shí)間和長(zhǎng)度,以微妙為單位。
通常,這個(gè)結(jié)構(gòu)由avformat_open_input在內(nèi)部創(chuàng)建并以缺省值初始化部分成員。但是,如果調(diào)用者希望自己創(chuàng)建該結(jié)構(gòu),則需要顯式為該結(jié)構(gòu)的一些成員置缺省值——如果沒有缺省值的話,會(huì)導(dǎo)致之后的動(dòng)作產(chǎn)生異常。以下成員需要被關(guān)注:
probesize
mux_rate
packet_size
flags
max_analyze_duration
key
max_index_size
max_picture_buffer
max_delay
AVPacket定義在avcodec.h中,如下:
[cpp] view plaincopy
typedef struct AVPacket {
/**
* Presentation timestamp in AVStream->time_base units; the time at which
* the decompressed packet will be presented to the user.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
* pts MUST be larger or equal to dts as presentation cannot happen before
* decompression, unless one wants to view hex dumps. Some formats misuse
* the terms dts and pts/cts to mean something different. Such timestamps
* must be converted to true pts/dts before they are stored in AVPacket.
*/
int64_t pts;
/**
* Decompression timestamp in AVStream->time_base units; the time at which
* the packet is decompressed.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
*/
int64_t dts;
uint8_t *data;
int   size;
int   stream_index;
int   flags;
/**
* Duration of this packet in AVStream->time_base units, 0 if unknown.
* Equals next_pts - this_pts in presentation order.
*/
int   duration;
void  (*destruct)(struct AVPacket *);
void  *priv;
int64_t pos;                            ///< byte position in stream, -1 if unknown
/**
* Time difference in AVStream->time_base units from the pts of this
* packet to the point at which the output from the decoder has converged
* independent from the availability of previous frames. That is, the
* frames are virtually identical no matter if decoding started from
* the very first frame or from this keyframe.
* Is AV_NOPTS_VALUE if unknown.
* This field is not the display duration of the current packet.
*
* The purpose of this field is to allow seeking in streams that have no
* keyframes in the conventional sense. It corresponds to the
* recovery point SEI in H.264 and match_time_delta in NUT. It is also
* essential for some types of subtitle streams to ensure that all
* subtitles are correctly displayed after seeking.
*/
int64_t convergence_duration;
} AVPacket;
FFMPEG使用AVPacket來暫存解復(fù)用之后、解碼之前的媒體數(shù)據(jù)(一個(gè)音/視頻幀、一個(gè)字幕包等)及附加信息(解碼時(shí)間戳、顯示時(shí)間戳、時(shí)長(zhǎng)等)。其中:
dts表示解碼時(shí)間戳,pts表示顯示時(shí)間戳,它們的單位是所屬媒體流的時(shí)間基準(zhǔn)。
stream_index給出所屬媒體流的索引;
data為數(shù)據(jù)緩沖區(qū)指針,size為長(zhǎng)度;
duration為數(shù)據(jù)的時(shí)長(zhǎng),也是以所屬媒體流的時(shí)間基準(zhǔn)為單位;
pos表示該數(shù)據(jù)在媒體流中的字節(jié)偏移量;
destruct為用于釋放數(shù)據(jù)緩沖區(qū)的函數(shù)指針;
flags為標(biāo)志域,其中,最低為置1表示該數(shù)據(jù)是一個(gè)關(guān)鍵幀。
AVPacket結(jié)構(gòu)本身只是個(gè)容器,它使用data成員引用實(shí)際的數(shù)據(jù)緩沖區(qū)。這個(gè)緩沖區(qū)通常是由av_new_packet創(chuàng)建的,但也可能由FFMPEG的API創(chuàng)建(如av_read_frame)。當(dāng)某個(gè)AVPacket結(jié)構(gòu)的數(shù)據(jù)緩沖區(qū)不再被使用時(shí),要需要通過調(diào)用av_free_packet釋放。av_free_packet調(diào)用的是結(jié)構(gòu)體本身的destruct函數(shù),它的值有兩種情況:1)av_destruct_packet_nofree或0;2)av_destruct_packet,其中,情況1)僅僅是將data和size的值清0而已,情況2)才會(huì)真正地釋放緩沖區(qū)。
FFMPEG內(nèi)部使用AVPacket結(jié)構(gòu)建立緩沖區(qū)裝載數(shù)據(jù),同時(shí)提供destruct函數(shù),如果FFMPEG打算自己維護(hù)緩沖區(qū),則將destruct設(shè)為av_destruct_packet_nofree,用戶調(diào)用av_free_packet清理緩沖區(qū)時(shí)并不能夠?qū)⑵溽尫?;如果FFMPEG打算將該緩沖區(qū)徹底交給調(diào)用者,則將destruct設(shè)為av_destruct_packet,表示它能夠被釋放。安全起見,如果用戶希望自由地使用一個(gè)FFMPEG內(nèi)部創(chuàng)建的AVPacket結(jié)構(gòu),最好調(diào)用av_dup_packet進(jìn)行緩沖區(qū)的克隆,將其轉(zhuǎn)化為緩沖區(qū)能夠被釋放的AVPacket,以免對(duì)緩沖區(qū)的不當(dāng)占用造成異常錯(cuò)誤。av_dup_packet會(huì)為destruct指針為av_destruct_packet_nofree的AVPacket新建一個(gè)緩沖區(qū),然后將原緩沖區(qū)的數(shù)據(jù)拷貝至新緩沖區(qū),置data的值為新緩沖區(qū)的地址,同時(shí)設(shè)destruct指針為av_destruct_packet。
時(shí)間信息用于實(shí)現(xiàn)多媒體同步。
同步的目的在于展示多媒體信息時(shí),能夠保持媒體對(duì)象之間固有的時(shí)間關(guān)系。同步有兩類,一類是流內(nèi)同步,其主要任務(wù)是保證單個(gè)媒體流內(nèi)的時(shí)間關(guān)系,以滿足感知要求,如按照規(guī)定的幀率播放一段視頻;另一類是流間同步,主要任務(wù)是保證不同媒體流之間的時(shí)間關(guān)系,如音頻和視頻之間的關(guān)系(lipsync)。
對(duì)于固定速率的媒體,如固定幀率的視頻或固定比特率的音頻,可以將時(shí)間信息(幀率或比特率)置于文件首部(header),如AVI的hdrl List、MP4的moov box,還有一種相對(duì)復(fù)雜的方案是將時(shí)間信息嵌入媒體流的內(nèi)部,如MPEG TS和Real video,這種方案可以處理變速率的媒體,亦可有效避免同步過程中的時(shí)間漂移。
FFMPEG會(huì)為每一個(gè)數(shù)據(jù)包打上時(shí)間標(biāo)簽,以更有效地支持上層應(yīng)用的同步機(jī)制。時(shí)間標(biāo)簽有兩種,一種是DTS,稱為解碼時(shí)間標(biāo)簽,另一種是PTS,稱為顯示時(shí)間標(biāo)簽。對(duì)于聲音來說 ,這兩個(gè)時(shí)間標(biāo)簽是相同的,但對(duì)于某些視頻編碼格式,由于采用了雙向預(yù)測(cè)技術(shù),會(huì)造成DTS和PTS的不一致。
無雙向預(yù)測(cè)幀的情況:
圖像類型: I P P P P P P ... I P PDTS: 0 1 2 3 4 5 6... 100 101 102PTS: 0 1 2 3 4 5 6... 100 101 102
有雙向預(yù)測(cè)幀的情況:
圖像類型: I P B B P B B ... I P BDTS: 0 1 2 3 4 5 6 ... 100 101 102PTS: 0 3 1 2 6 4 5 ... 100 104 102
對(duì)于存在雙向預(yù)測(cè)幀的情況,通常要求解碼器對(duì)圖像重排序,以保證輸出的圖像順序?yàn)轱@示順序:
解碼器輸入:I P B B P B B (DTS) 0 1 2 3 4 5 6 (PTS) 0 3 1 2 6 4 5解碼器輸出:X I B B P B B P (PTS) X 0 1 2 3 4 5 6
時(shí)間信息的獲取:
通過調(diào)用avformat_find_stream_info,多媒體應(yīng)用可以從AVFormatContext對(duì)象中拿到媒體文件的時(shí)間信息:主要是總時(shí)間長(zhǎng)度和開始時(shí)間,此外還有與時(shí)間信息相關(guān)的比特率和文件大小。其中時(shí)間信息的單位是AV_TIME_BASE:微秒。
[cpp] view plaincopy
typedef struct AVFormatContext {
......
/** Decoding: position of the first frame of the component, in
AV_TIME_BASE fractional seconds. NEVER set this value directly:
It is deduced from the AVStream values.  */
int64_t start_time;
/** Decoding: duration of the stream, in AV_TIME_BASE fractional
seconds. Only set this value if you know none of the individual stream
durations and also dont set any of them. This is deduced from the
AVStream values if not set.  */
int64_t duration;
/** decoding: total file size, 0 if unknown */
int64_t file_size;
/** Decoding: total stream bitrate in bit/s, 0 if not
available. Never set it directly if the file_size and the
duration are known as FFmpeg can compute it automatically. */
int bit_rate;
......
} AVFormatContext;
以上4個(gè)成員變量都是只讀的,基于FFMpeg的中間件需要將其封裝到某個(gè)接口中,如:
[cpp] view plaincopy
LONG GetDuratioin(IntfX*);
LONG GetStartTime(IntfX*);
LONG GetFileSize(IntfX*);
LONG GetBitRate(IntfX*);
int avformat_open_input(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, AVDictionary **options);
avformat_open_input完成兩個(gè)任務(wù):
打開一個(gè)文件或URL,基于字節(jié)流的底層輸入模塊得到初始化。
解析多媒體文件或多媒體流的頭信息,創(chuàng)建AVFormatContext結(jié)構(gòu)并填充其中的關(guān)鍵字段,依次為各個(gè)原始流建立AVStream結(jié)構(gòu)。
一個(gè)多媒體文件或多媒體流與其包含的原始流的關(guān)系如下:
多媒體文件/多媒體流 (movie.mkv) 原始流 1 (h.264 video) 原始流 2 (aac audio for Chinese) 原始流 3 (aac audio for english) 原始流 4 (Chinese Subtitle) 原始流 5 (English Subtitle) ...
關(guān)于輸入?yún)?shù):
ic_ptr,這是一個(gè)指向指針的指針,用于返回avformat_open_input內(nèi)部構(gòu)造的一個(gè)AVFormatContext結(jié)構(gòu)體。
filename,指定文件名。
fmt,用于顯式指定輸入文件的格式,如果設(shè)為空則自動(dòng)判斷其輸入格式。
options
這個(gè)函數(shù)通過解析多媒體文件或流的頭信息及其他輔助數(shù)據(jù),能夠獲取足夠多的關(guān)于文件、流和編解碼器的信息,但由于任何一種多媒體格式提供的信息都是有限的,而且不同的多媒體內(nèi)容制作軟件對(duì)頭信息的設(shè)置不盡相同,此外這些軟件在產(chǎn)生多媒體內(nèi)容時(shí)難免會(huì)引入一些錯(cuò)誤,因此這個(gè)函數(shù)并不保證能夠獲取所有需要的信息,在這種情況下,則需要考慮另一個(gè)函數(shù):avformat_find_stream_info。
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
這個(gè)函數(shù)主要用于獲取必要的編解碼器參數(shù),設(shè)置到ic→streams[i]→codec中。
首先必須得到各媒體流對(duì)應(yīng)編解碼器的類型和id,這是兩個(gè)定義在avutils.h和avcodec.h中的枚舉:
[cpp] view plaincopy
enum AVMediaType {
AVMEDIA_TYPE_UNKNOWN = -1,
AVMEDIA_TYPE_VIDEO,
AVMEDIA_TYPE_AUDIO,
AVMEDIA_TYPE_DATA,
AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_ATTACHMENT,
AVMEDIA_TYPE_NB
};
enum CodecID {
CODEC_ID_NONE,
/* video codecs */
CODEC_ID_MPEG1VIDEO,
CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
CODEC_ID_MPEG2VIDEO_XVMC,
CODEC_ID_H261,
CODEC_ID_H263,
...
};
通常,如果某種媒體格式具備完備而正確的頭信息,調(diào)用avformat_open_input即可以得到這兩個(gè)參數(shù),但若是因某種原因avformat_open_input無法獲取它們,這一任務(wù)將由avformat_find_stream_info完成。
其次還要獲取各媒體流對(duì)應(yīng)編解碼器的時(shí)間基準(zhǔn)。
此外,對(duì)于音頻編解碼器,還需要得到:
采樣率,
聲道數(shù),
位寬,
幀長(zhǎng)度(對(duì)于某些編解碼器是必要的),
對(duì)于視頻編解碼器,則是:
圖像大小,
色彩空間及格式,
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
這個(gè)函數(shù)用于從多媒體文件或多媒體流中讀取媒體數(shù)據(jù),獲取的數(shù)據(jù)由AVPacket結(jié)構(gòu)pkt來存放。對(duì)于音頻數(shù)據(jù),如果是固定比特率,則pkt中裝載著一個(gè)或多個(gè)音頻幀;如果是可變比特率,則pkt中裝載有一個(gè)音頻幀。對(duì)于視頻數(shù)據(jù),pkt中裝載有一個(gè)視頻幀。需要注意的是:再次調(diào)用本函數(shù)之前,必須使用av_free_packet釋放pkt所占用的資源。
通過pkt→stream_index可以查到獲取的媒體數(shù)據(jù)的類型,從而將數(shù)據(jù)送交相應(yīng)的解碼器進(jìn)行后續(xù)處理。
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
這個(gè)函數(shù)通過改變媒體文件的讀寫指針來實(shí)現(xiàn)對(duì)媒體文件的隨機(jī)訪問,支持以下三種方式:
基于時(shí)間的隨機(jī)訪問:具體而言就是將媒體文件讀寫指針定位到某個(gè)給定的時(shí)間點(diǎn)上,則之后調(diào)用av_read_frame時(shí)能夠讀到時(shí)間標(biāo)簽等于給定時(shí)間點(diǎn)的媒體數(shù)據(jù),通常用于實(shí)現(xiàn)媒體播放器的快進(jìn)、快退等功能。
基于文件偏移的隨機(jī)訪問:相當(dāng)于普通文件的seek函數(shù),timestamp也成為文件的偏移量。
基于幀號(hào)的隨機(jī)訪問:timestamp為要訪問的媒體數(shù)據(jù)的幀號(hào)。
關(guān)于參數(shù):
s:是個(gè)AVFormatContext指針,就是avformat_open_input返回的那個(gè)結(jié)構(gòu)。
stream_index:指定媒體流,如果是基于時(shí)間的隨機(jī)訪問,則第三個(gè)參數(shù)timestamp將以此媒體流的時(shí)間基準(zhǔn)為單位;如果設(shè)為負(fù)數(shù),則相當(dāng)于不指定具體的媒體流,F(xiàn)FMPEG會(huì)按照特定的算法尋找缺省的媒體流,此時(shí),timestamp的單位為AV_TIME_BASE(微秒)。
timestamp:時(shí)間標(biāo)簽,單位取決于其他參數(shù)。
flags:定位方式,AVSEEK_FLAG_BYTE表示基于字節(jié)偏移,AVSEEK_FLAG_FRAME表示基于幀號(hào),其它表示基于時(shí)間。
void av_close_input_file(AVFormatContext *s);
關(guān)閉一個(gè)媒體文件:釋放資源,關(guān)閉物理IO。
AVCodec *avcodec_find_decoder(enum CodecID id);AVCodec *avcodec_find_decoder_by_name(const char *name);
根據(jù)給定的codec id或解碼器名稱從系統(tǒng)中搜尋并返回一個(gè)AVCodec結(jié)構(gòu)的指針。
int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
此函數(shù)根據(jù)輸入的AVCodec指針具體化AVCodecContext結(jié)構(gòu)。在調(diào)用該函數(shù)之前,需要首先調(diào)用avcodec_alloc_context分配一個(gè)AVCodecContext結(jié)構(gòu),或調(diào)用avformat_open_input獲取媒體文件中對(duì)應(yīng)媒體流的AVCodecContext結(jié)構(gòu);此外還需要通過avcodec_find_decoder獲取AVCodec結(jié)構(gòu)。
這一函數(shù)還將初始化對(duì)應(yīng)的解碼器。
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt);
解碼一個(gè)視頻幀。got_picture_ptr指示是否有解碼數(shù)據(jù)輸出。
輸入數(shù)據(jù)在AVPacket結(jié)構(gòu)中,輸出數(shù)據(jù)在AVFrame結(jié)構(gòu)中。AVFrame是定義在avcodec.h中的一個(gè)數(shù)據(jù)結(jié)構(gòu):
typedef struct AVFrame { FF_COMMON_FRAME} AVFrame;
FF_COMMON_FRAME定義了諸多數(shù)據(jù)域,大部分由FFMpeg內(nèi)部使用,對(duì)于用戶來說,比較重要的主要包括:
#define FF_COMMON_FRAME ...... uint8_t *data[4]; int linesize[4]; int key_frame; int pict_type; int64_t pts;\ int reference;\ ......
FFMpeg內(nèi)部以planar的方式存儲(chǔ)原始圖像數(shù)據(jù),即將圖像像素分為多個(gè)平面(R/G/B或Y/U/V),data數(shù)組內(nèi)的指針分別指向四個(gè)像素平面的起始位置,linesize數(shù)組則存放各個(gè)存貯各個(gè)平面的緩沖區(qū)的行寬:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++data[0]->#################################++++++++++++++++++++++++###########picture data##########++++++++++++++++++++++++#################################++++++++++++++++++++++++#################################++++++++++++ ........................++++++++++++#################################++++++++++++|<-------------------line_size[0]---------------------->|
此外,key_frame標(biāo)識(shí)該圖像是否是關(guān)鍵幀;pict_type表示該圖像的編碼類型:I(1)/P(2)/B(3)……;pts是以time_base為單位的時(shí)間標(biāo)簽,對(duì)于部分解碼器如H.261、H.263和MPEG4,可以從頭信息中獲?。籸eference表示該圖像是否被用作參考。
int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt);
解碼一個(gè)音頻幀。輸入數(shù)據(jù)在AVPacket結(jié)構(gòu)中,輸出數(shù)據(jù)在frame中,got_frame_ptr表示是否有數(shù)據(jù)輸出。
int avcodec_close(AVCodecContext *avctx);
關(guān)閉解碼器,釋放avcodec_open中分配的資源。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
FFMPEG解碼流程1(轉(zhuǎn))
FFmpeg 學(xué)習(xí)(七):FFmpeg 學(xué)習(xí)整理總結(jié)
FFmpeg學(xué)習(xí)教程
FFMPEG
ffmpeg解碼函數(shù)簡(jiǎn)介
ffmpeg函數(shù)介紹
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服