FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。
Fmpeg 是领先的多媒体框架,能够解码、编码、转码、混合、解密、流媒体、过滤和播放人类和机器创造的几乎所有东西。它支持最晦涩的古老格式,直到最尖端的格式。无论它们是由某个标准委员会、社区还是公司设计的。它还具有高度的便携性。

const char *name:编解码器的名字,比较短
const char *long_name:编解码器的名字,全称,比较长
enum AVMediaType type:指明了类型,是视频,音频,还是字幕
enum AVCodecID id:ID,音视频流ID信息,枚举类型
const AVRational *supported_framerates:支持的帧率(仅视频)
const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
const int *supported_samplerates:支持的采样率(仅音频)
const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
const uint64_t *channel_layouts:支持的声道数(仅音频)
int priv_data_size:私有数据的大小
AVIOContext *pb;字节流IO上下文
unsigned int nb_streams;音视频流个数
AVStream **streams;音视频流
char filename[1024];输入输出文件名
int64_t duration;流持续时间,即总时长,单位为us
int bit_rate:比特率(码率)(单位bps,转换为kbps需要除以1000)
AVDictionary *metadata:元数据
可以读取电脑(或其他设备上)的多媒体设备的数据,或者输出到指定的多媒体设备上。
libavfilter提供了一个通用的音视频filter框架。使用avfilter可以对音视频数据做一些效果处理如去色调、模糊、水平翻转、裁剪、加方框、叠加文字等功能。
libswscale 是 FFmpeg 中完成图像尺寸缩放和像素格式转换的库。用户可以编写程序,调用 libswscale 提供的 API 来进行图像尺寸缩放和像素格式转换。
libswscale中常用函数:
sws_getContext();初始化一个SwsContext。
sws_scale();处理图像数据。
sws_freeContext();释放一个SwsContext。
libswresample库功能主要包括高度优化的音频重采样、rematrixing和样本格式转换操作。
(同步、时间计算的简单算法)用于后期效果处理;
开发平台: ubuntu18.04.6
ffmpeg版本: 4.2.5
SDL版本: 2.0.14
#include <stdio.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include <libswresample/swresample.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <stdio.h>
#include <linux/fb.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <poll.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <wchar.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL.h>
#define FILE_NAME "123.flv"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef enum
{
false,
true,
}bool;
uint8_t *out_buffer;
#define MAX_AUDIO_FRAME_SIZE 1024*100
static Uint8* audio_chunk;
static unsigned int audio_len=0;
static unsigned char *audio_pos;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
//保存音频数据链表
struct AUDIO_DATA
{
unsigned char* audio_buffer;
int audio_size;
struct AUDIO_DATA *next;
};
//定义一个链表头
struct AUDIO_DATA *list_head=NULL;
struct AUDIO_DATA *List_CreateHead(struct AUDIO_DATA *head);//创建链表头
void List_AddNode(struct AUDIO_DATA *head,unsigned char* audio_buffer,int audio_size);//添加节点
void List_DelNode(struct AUDIO_DATA *head,unsigned char* audio_buffer);//删除节点
int List_GetNodeCnt(struct AUDIO_DATA *head);//遍历
int List_GetNode(struct AUDIO_DATA *head,char *audio_buff,int *audio_size);
int file_stat=1;
void AudioCallback(void *userdata, Uint8 * stream,int len)
{
SDL_memset(stream, 0,len);
if(audio_len<=0)
{
return ;
}
len=(len>audio_len?audio_len:len);
SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME);
audio_pos+=len;
audio_len-=len;
//printf("len=%d\n",len);
}
void *Audio_decode(void *arg)
{
int res;
int audio_size;
char audio_buff[4096*3];
while(1)
{
res=List_GetNode(list_head,audio_buff,&audio_size);
if(res==0)
{
audio_chunk = audio_buff; //指向音频数据 (PCM data)
while(audio_len>0){}//等待数据处理完
audio_len =audio_size;//音频长度
audio_pos = audio_buff;//当前播放位置
}
}
}
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("格式:./app 文件名\n");
return 0;
}
char *file_name=argv[1];
/*SDL初始化*/
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER);
printf("pth:%s\n",avcodec_configuration());/*获取ffmpeg配置信息*/
/*初始化所有组件*/
//av_register_all();
/*打开文件*/
AVCodecContext *pCodecCtx;//解码器上下文
AVFormatContext *ps=NULL;//音视频封装格式结构体信息
printf("name:%s\n",file_name);
int res=avformat_open_input(&ps,file_name,NULL,NULL);
if(res!=0)
{
printf("open err: %d\n",res);
return 0;
}
/*寻找解码信息*/
avformat_find_stream_info(ps,NULL);
int64_t time=ps->duration;
printf("time:%ld s\n",time/1000000);
/*打印有关输入或输出格式的详细信息*/
av_dump_format(ps,0,file_name,0);
/*寻找视频流信息*/
int videostream=-1;
int audiostream=-1;
AVCodec *vcodec;
videostream=av_find_best_stream(ps,AVMEDIA_TYPE_VIDEO,-1,-1,NULL, 0);
printf("video=%d\n",videostream);
/*寻找音频流信息*/
audiostream=av_find_best_stream(ps,AVMEDIA_TYPE_AUDIO,-1,-1,NULL, 0);
printf("audio=%d\n",audiostream);
AVStream *stream;
int frame_rate;
if(videostream!=-1)//判断是否找到视频流数据
{
/*寻找视频解码器*/
AVStream *stream = ps->streams[videostream];
vcodec=avcodec_find_decoder(stream->codecpar->codec_id);
if(!vcodec)
{
printf("未找到视频解码器\n");
return -1;
}/*申请AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。*/
res=avcodec_open2(stream->codec,vcodec,NULL);
if(res)
{
printf("打开解码器失败\n");
return -1;
}
frame_rate=stream->avg_frame_rate.num/stream->avg_frame_rate.den;//每秒多少帧
printf("fps=%d\n",frame_rate);
printf("视频流ID=%#x\n",vcodec->id);//音频流
}
/*音频流数据处理*/
AVCodec *audcodec;
AVStream *audstream;
SwrContext *swrCtx;//保存重采样数据,即解码的信息
uint64_t out_channel_layout;//声道
int out_sample_fmt;//采样格式
int out_sample_rate;//采样率
int out_nb_samples;//样本数量
int out_channels;//通道数量
uint64_t in_channel_layout;//输入音频声道
SDL_AudioSpec desired;//SDL音频格式信息
AVFrame *audioframe;//保存音频数据
int out_buffer_size;//音频缓冲区大小
if(audiostream>=0)//判断是否有音频流
{
/*寻找音频解码器*/
audstream = ps->streams[audiostream];
audcodec=avcodec_find_decoder(audstream->codecpar->codec_id);
if(!audcodec)
{
printf("audcodec failed\n");
return -1;
}
/*申请音频AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。*/
pCodecCtx=audstream->codec;//解码器上下文
res=avcodec_open2(audstream->codec,audcodec,NULL);
if(res)
{
printf("未找到音频解码器\n");
return -1;
}
printf("音频流ID=%#x\n",audcodec->id);//音频流
printf("配置音频参数\n");
//输出音频参数
out_channel_layout = AV_CH_LAYOUT_STEREO; //声道格式
out_sample_fmt=AV_SAMPLE_FMT_S16;//AV_SAMPLE_FMT_S32;//;//采样格式
printf("pCodecCtx->sample_rate=%d\n",pCodecCtx->sample_rate);
out_sample_rate =pCodecCtx->sample_rate;//采样率,多为44100
/*样本数量*/
printf("frame_size=%d\n",pCodecCtx->frame_size);
if(pCodecCtx->frame_size>0)out_nb_samples=pCodecCtx->frame_size;
else if(audcodec->id == AV_CODEC_ID_AAC) out_nb_samples=1024;/*样本数量nb_samples: AAC-1024 MP3-1152 格式大小 */
else if(audcodec->id == AV_CODEC_ID_MP3)out_nb_samples=1152;
else out_nb_samples=1024;
out_channels=av_get_channel_layout_nb_channels(out_channel_layout);//通道个数
out_buffer_size=av_samples_get_buffer_size(NULL,out_channels,out_nb_samples,out_sample_fmt,1);//获取缓冲区大小
out_buffer=(uint8_t*)av_malloc(MAX_AUDIO_FRAME_SIZE);
memset(out_buffer,0,out_buffer_size);
printf("声道格式:%d\n",out_channel_layout);
printf("采样格式:%d\n",out_sample_fmt);
printf("样本数量:%d\n",out_nb_samples);
printf("采样率:%d\n",out_sample_rate);
printf("通道个数:%d\n",out_channels);
printf("缓冲区大小:%d\n",out_buffer_size);
//输入音频参数
in_channel_layout=av_get_default_channel_layout(pCodecCtx->channels);//输入声道格式
swrCtx = swr_alloc();
/*对解码数据进行重采样*/
swrCtx=swr_alloc_set_opts(swrCtx,out_channel_layout,out_sample_fmt,out_sample_rate,/*输入音频格式*/
in_channel_layout,pCodecCtx->sample_fmt,pCodecCtx->sample_rate,/*输出音频格式*/
0,NULL);
swr_init(swrCtx);//初始化swrCtx
printf("输入音频格式:%d\n",in_channel_layout);
printf("输入采样格式:%d\n",pCodecCtx->sample_fmt);
printf("输入采样率:%d\n",pCodecCtx->sample_rate);
/*设置音频数据格式*/
desired.freq=out_sample_rate;/*采样率*/
desired.format=AUDIO_S16SYS;/*无符号16位*/
desired.channels=out_channels;/*声道*/
desired.samples=out_nb_samples;/*样本数1024*/
desired.silence=0;/*静音值*/
desired.callback=AudioCallback;
SDL_OpenAudio(&desired,NULL);
SDL_PauseAudio(0);/*开始播放音频,1为播放静音值*/
//分配内存
audioframe=av_frame_alloc();/*分配音频帧*/
printf("音频数据初始化完成");
}
//视频解码
AVFrame *frame=av_frame_alloc();/*分配视频帧*/
AVFrame *frameYUV=av_frame_alloc();/*申请yuv空间*/
/*分配空间,进行图像转换*/
int width=ps->streams[videostream]->codecpar->width;
int height=ps->streams[videostream]->codecpar->height;
int fmt=ps->streams[videostream]->codecpar->format;/*流格式*/
printf("fmt=%d\n",fmt);
int size=avpicture_get_size(AV_PIX_FMT_RGB24, width,height);
unsigned char *buff=NULL;
printf("w=%d,h=%d,size=%d\n",width,height,size);
buff=av_malloc(size);
/*计算一帧空间大小*/
avpicture_fill((AVPicture *)frameYUV,buff,AV_PIX_FMT_RGB24,width,height);
/*转换上下文*/
struct SwsContext *swsctx=sws_getContext(width,height, fmt,width,height, AV_PIX_FMT_RGB24,SWS_BICUBIC,NULL,NULL,NULL);
/*读帧*/
int go=0;
int go_audio;
list_head=List_CreateHead(list_head);//创建链表头
/*创建音频处理线程*/
pthread_t pthid;
pthread_create(&pthid,NULL,Audio_decode,(void *)ps);
pthread_detach(pthid);//设置为分离属性
/*创建窗口*/
SDL_Window *window=SDL_CreateWindow("SDL_VIDEO", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,1280,720,SDL_WINDOW_SHOWN);
/*创建渲染器*/
SDL_Renderer *render=SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
/*清空渲染器*/
SDL_RenderClear(render);
/*创建纹理*/
SDL_Texture *sdltext=SDL_CreateTexture(render,SDL_PIXELFORMAT_RGB24,SDL_TEXTUREACCESS_STREAMING,width,height);
bool quit=true;
SDL_Event event;
printf("read fream buff\n");
//初始化转码器
AVPacket *packet=av_malloc(sizeof(AVPacket));/*分配包*/
av_init_packet(packet);//初始化
int i=0;
int index=0;
long video_pts_time=0;
long audio_pts_time=0;//音频解码时间
time=(1000000/frame_rate-10000);//时间
printf("time=%d\n",time);
while((av_read_frame(ps,packet)>=0) && (quit))
{
SDL_PollEvent(&event);
if(event.type==SDL_QUIT)
{
quit=false;
continue;
}
if(packet->stream_index == videostream)/*判断是否为视频*/
{
res=avcodec_send_packet(ps->streams[videostream]->codec,packet);
if(res)
{
av_packet_unref(packet);//释放这个pkt
continue;
}
res=avcodec_receive_frame(ps->streams[videostream]->codec,frame);
if(res)
{
av_packet_unref(packet);//释放这个pkt
continue;
}
sws_scale(swsctx,(const uint8_t **)frame->data,frame->linesize,0,height,(const uint8_t **)frameYUV->data,frameYUV->linesize);
video_pts_time=packet->pts;
//printf("视频=%ld\n",video_pts_time);
SDL_UpdateTexture(sdltext,NULL,buff, width*3);
SDL_RenderCopy(render, sdltext, NULL, NULL); // 拷贝纹理到渲染器
SDL_RenderPresent(render); //渲染
usleep(time);
}
if(packet->stream_index == audiostream) //如果为音频标志
{
if(audiostream<0)continue;
res=avcodec_send_packet(pCodecCtx,packet);
if(res)
{
printf("avcodec_send_packet failed,res=%d\n",res);
av_packet_unref(packet);//释放这个pkt
continue;
}
res=avcodec_receive_frame(pCodecCtx,audioframe);
if(res)
{
printf("avcodec_receive_frame failed,res=%d\n",res);
av_packet_unref(packet);//释放这个pkt
continue;
}
//数据格式转换
res=swr_convert(swrCtx,&out_buffer,out_buffer_size,/*重采样之后的数据*/
(const uint8_t **)audioframe->data,audioframe->nb_samples/*重采样之前数据*/
);
audio_pts_time=packet->pts;
//printf("音频:%ld\n",audio_pts_time);
if(res>0)
{
//audio_chunk =out_buffer; //指向音频数据 (PCM data)
//while(audio_len>0){}//等待数据处理完
//audio_len =audioframe->nb_samples;//out_buffer_size;//音频长度
//audio_pos =out_buffer;//当前播放位置
List_AddNode(list_head,out_buffer,out_buffer_size);//添加节点
}
}
//释放数据包
av_packet_unref(packet);
}
sws_freeContext(swsctx);
av_frame_free(&frame);
av_frame_free(&frameYUV);
avformat_free_context(ps);
return 0;
}
/*创建链表头*/
struct AUDIO_DATA *List_CreateHead(struct AUDIO_DATA *head)
{
if(head==NULL)
{
head=malloc(sizeof(struct AUDIO_DATA));
head->next=NULL;
}
return head;
}
/*添加节点*/
void List_AddNode(struct AUDIO_DATA *head,unsigned char* audio_buffer,int audio_size)
{
struct AUDIO_DATA *tmp=head;
struct AUDIO_DATA *new_node;
pthread_mutex_lock(&mutex);
/*找到链表尾部*/
while(tmp->next)
{
tmp=tmp->next;
}
/*插入新的节点*/
new_node=malloc(sizeof(struct AUDIO_DATA));
new_node->audio_size=audio_size;
new_node->audio_buffer=malloc(audio_size);//分配保存音频数据大小空间
memcpy(new_node->audio_buffer,audio_buffer,audio_size);
new_node->next=NULL;
/*将新节点接入到链表*/
tmp->next=new_node;
pthread_mutex_unlock(&mutex);
}
/*
函数功能:删除节点
*/
void List_DelNode(struct AUDIO_DATA *head,unsigned char* audio_buffer)
{
struct AUDIO_DATA *tmp=head;
struct AUDIO_DATA *p;
/*找到链表中要删除的节点*/
pthread_mutex_lock(&mutex);
while(tmp->next)
{
p=tmp;
tmp=tmp->next;
if(tmp->audio_buffer==audio_buffer)
{
p->next=tmp->next;
free(tmp->audio_buffer);
free(tmp);
break;
}
}
pthread_mutex_unlock(&mutex);
}
/*
函数功能:遍历链表,得到节点总数量
*/
int List_GetNodeCnt(struct AUDIO_DATA *head)
{
int cnt=0;
struct AUDIO_DATA *tmp=head;
pthread_mutex_lock(&mutex);
while(tmp->next)
{
tmp=tmp->next;
cnt++;
}
pthread_mutex_unlock(&mutex);
return cnt;
}
/*
从链表头取数据
*/
int List_GetNode(struct AUDIO_DATA *head,char *audio_buff,int *audio_size)
{
struct AUDIO_DATA *tmp=head;
struct AUDIO_DATA *ptemp=head;
pthread_mutex_lock(&mutex);
while(tmp->next!=NULL)
{
ptemp=tmp;
tmp=tmp->next;
if(tmp!=NULL)
{
*audio_size=tmp->audio_size;
memcpy(audio_buff,tmp->audio_buffer,tmp->audio_size);
ptemp->next=tmp->next;
free(tmp->audio_buffer);
free(tmp);
pthread_mutex_unlock(&mutex);
return 0;
}
}
pthread_mutex_unlock(&mutex);
return -1;
}
OBJ=main.o
CFLAGS=-I/home/wbyq/src_pack/ffmpeg-4.2.5/_install/include -L/home/wbyq/src_pack/ffmpeg-4.2.5/_install/lib\
-I/home/wbyq/src_pack/SDL2-2.0.14/_install/include -I/home/wbyq/src_pack/SDL2-2.0.14/_install/include/SDL2 -L/home/wbyq/src_pack/SDL2-2.0.14/_install/lib \
-lSDL2 -lpthread -lm -ldl -lavcodec -lavfilter -lavutil -lswresample -lavdevice -lavformat -lpostproc -lswscale -lpthread -lstdc++ -lm -lasound -lx264
app:$(OBJ)
gcc -o $@ $^ $(CFLAGS)


导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、
2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope
我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源
目前我正在使用这个正则表达式从YoutubeURL中提取视频ID:url.match(/v=([^&]*)/)[1]我怎样才能改变它,以便它也可以从这个没有v参数的YoutubeURL获取视频ID:http://www.youtube.com/user/SHAYTARDS#p/u/9/Xc81AajGUMU感谢阅读。编辑:我正在使用ruby1.8.7 最佳答案 对于Ruby1.8.7,这就可以了。url_1='http://www.youtube.com/watch?v=8WVTOUh53QY&feature=feedf'url
我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n