puremotion 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.yardopts +1 -0
  2. data/README.md +69 -0
  3. data/Rakefile +23 -11
  4. data/examples/progress_reporting.rb +26 -0
  5. data/examples/simple.rb +22 -0
  6. data/ext/puremotion/audio.c +38 -0
  7. data/ext/puremotion/extconf.rb +34 -0
  8. data/ext/puremotion/frame.c +176 -0
  9. data/ext/puremotion/media.c +175 -0
  10. data/ext/puremotion/puremotion.c +26 -0
  11. data/ext/puremotion/puremotion.h +38 -0
  12. data/ext/puremotion/stream.c +128 -0
  13. data/ext/puremotion/stream_collection.c +44 -0
  14. data/ext/puremotion/utils.c +81 -0
  15. data/ext/puremotion/utils.h +6 -0
  16. data/ext/puremotion/video.c +141 -0
  17. data/lib/{puremotion/events → events}/event.rb +0 -0
  18. data/lib/{puremotion/events → events}/generator.rb +0 -0
  19. data/lib/media.rb +89 -0
  20. data/lib/preset/audio/audio.rb +42 -0
  21. data/lib/preset/file.rb +19 -0
  22. data/lib/preset/general.rb +28 -0
  23. data/lib/preset/metadata.rb +41 -0
  24. data/lib/preset/preset.rb +120 -0
  25. data/lib/preset/video/crop.rb +29 -0
  26. data/lib/preset/video/pad.rb +31 -0
  27. data/lib/preset/video/video.rb +130 -0
  28. data/lib/puremotion.rb +20 -12
  29. data/lib/puremotion_native.so +0 -0
  30. data/lib/threading.rb +54 -0
  31. data/lib/{puremotion/tools → tools}/ffmpeg.rb +12 -50
  32. data/lib/transcode/transcode.rb +142 -0
  33. data/spec/spec_helper.rb +7 -0
  34. data/spec/units/media_spec.rb +13 -0
  35. data/spec/units/preset_spec.rb +91 -0
  36. metadata +52 -44
  37. data/.document +0 -5
  38. data/.gitignore +0 -21
  39. data/README.rdoc +0 -18
  40. data/VERSION +0 -1
  41. data/lib/puremotion/codecs.rb +0 -59
  42. data/lib/puremotion/media.rb +0 -490
  43. data/lib/puremotion/media/stream.rb +0 -4
  44. data/lib/puremotion/media/stream/audio.rb +0 -0
  45. data/lib/puremotion/media/stream/base.rb +0 -7
  46. data/lib/puremotion/media/stream/collection.rb +0 -5
  47. data/lib/puremotion/media/stream/video.rb +0 -61
  48. data/lib/puremotion/recipes/ipod.yml +0 -12
  49. data/lib/puremotion/thread.rb +0 -153
  50. data/lib/puremotion/transcode/recipe.rb +0 -250
  51. data/lib/puremotion/transcode/transcode.rb +0 -153
  52. data/puremotion.gemspec +0 -68
  53. data/test/helper.rb +0 -10
  54. data/test/test_puremotion.rb +0 -7
@@ -0,0 +1,26 @@
1
+ #include "puremotion.h"
2
+
3
+ VALUE rb_mPureMotion;
4
+ VALUE rb_mStreams;
5
+
6
+ void Init_puremotion_native() {
7
+
8
+ av_register_all();
9
+ avcodec_register_all();
10
+
11
+ // Don't sent all output into ruby interpreter
12
+ // This will eventually be changed by calling av_log_callback
13
+ // If you want to develop it's best you set this to AV_LOG_VERBOSE
14
+ av_log_set_level(AV_LOG_QUIET);
15
+
16
+ rb_mPureMotion = rb_define_module("PureMotion");
17
+ rb_mStreams = rb_define_module_under(rb_mPureMotion, "Streams");
18
+
19
+ Init_media();
20
+ Init_stream();
21
+ Init_video_stream();
22
+ Init_audio_stream();
23
+ Init_stream_collection();
24
+ Init_frame();
25
+
26
+ }
@@ -0,0 +1,38 @@
1
+ #include <libavformat/avformat.h>
2
+ #include <libavutil/avutil.h>
3
+ #include <libavcodec/avcodec.h>
4
+ #include <libswscale/swscale.h>
5
+ #include <gd.h>
6
+
7
+ #ifdef RSHIFT
8
+ #undef RSHIFT
9
+ #endif
10
+
11
+ #define DEBUG
12
+
13
+ #include "ruby.h"
14
+
15
+ RUBY_EXTERN VALUE rb_mPureMotion;
16
+ RUBY_EXTERN VALUE rb_mStreams;
17
+ RUBY_EXTERN VALUE rb_cMedia;
18
+ RUBY_EXTERN VALUE rb_cStream;
19
+ RUBY_EXTERN VALUE rb_cVideoStream;
20
+ RUBY_EXTERN VALUE rb_cAudioStream;
21
+ RUBY_EXTERN VALUE rb_cStreamCollection;
22
+ RUBY_EXTERN VALUE rb_cFrame;
23
+
24
+ RUBY_EXTERN VALUE rb_eUnsupportedFormat;
25
+
26
+ RUBY_EXTERN void Init_puremotion_native();
27
+ RUBY_EXTERN void Init_media();
28
+ RUBY_EXTERN void Init_stream();
29
+ RUBY_EXTERN void Init_video_stream();
30
+ RUBY_EXTERN void Init_audio_stream();
31
+ RUBY_EXTERN void Init_stream_collection();
32
+ RUBY_EXTERN void Init_frame();
33
+
34
+ VALUE build_stream_collection(VALUE media);
35
+ VALUE build_stream(AVStream *stream, VALUE rb_media);
36
+ VALUE build_video_stream(AVStream *stream, VALUE rb_media);
37
+ VALUE build_audio_stream(AVStream *stream, VALUE rb_media);
38
+ VALUE build_frame_object(AVFrame * frame, int width, int height, int pixel_format);
@@ -0,0 +1,128 @@
1
+ #include "puremotion.h"
2
+ #include "utils.h"
3
+
4
+ VALUE rb_cStream;
5
+ VALUE rb_mStreams;
6
+
7
+ static int next_packet(AVFormatContext * format_context, AVPacket * packet)
8
+ {
9
+ if(packet->data != NULL)
10
+ av_free_packet(packet);
11
+
12
+ if(av_read_frame(format_context, packet) < 0) {
13
+ return -1;
14
+ }
15
+
16
+ return 0;
17
+ }
18
+
19
+ static int next_packet_for_stream(AVFormatContext * format_context, int stream_index, AVPacket * packet)
20
+ {
21
+ int ret = 0;
22
+ do {
23
+ ret = next_packet(format_context, packet);
24
+ } while(packet->stream_index != stream_index && ret == 0);
25
+
26
+ return ret;
27
+ }
28
+
29
+ static VALUE stream_type( VALUE self ) {
30
+ AVStream * stream = get_stream(self);
31
+
32
+ VALUE type = rb_sym("unknown");
33
+
34
+ switch( stream->codec->codec_type ) {
35
+ case CODEC_TYPE_AUDIO:
36
+ type = rb_sym("audio");
37
+ break;
38
+ case CODEC_TYPE_VIDEO:
39
+ type = rb_sym("video");
40
+ break;
41
+ }
42
+
43
+ return type;
44
+
45
+ }
46
+
47
+ static VALUE stream_duration(VALUE self) {
48
+ AVStream *stream = get_stream(self);
49
+
50
+ if (stream->duration == AV_NOPTS_VALUE) return Qnil;
51
+
52
+ return (rb_float_new(stream->duration * av_q2d(stream->time_base)));
53
+ }
54
+
55
+ static VALUE stream_seek(VALUE self, VALUE position) {
56
+ AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
57
+ AVStream * stream = get_stream(self);
58
+
59
+ int64_t timestamp = NUM2LONG(position) / av_q2d(stream->time_base);
60
+
61
+ int ret;
62
+ if (format_context->start_time != AV_NOPTS_VALUE)
63
+ timestamp += format_context->start_time;
64
+
65
+ //fprintf(stderr, "seeking to %d\n", NUM2INT(position));
66
+ ret = av_seek_frame(format_context, stream->index, timestamp, 0);
67
+ if (ret < 0) {
68
+ rb_raise(rb_eRangeError, "could not seek %s to pos %f",
69
+ format_context->filename, timestamp * av_q2d(stream->time_base));
70
+ }
71
+
72
+ //fprintf(stderr, "seeked.\n");
73
+ return self;
74
+ }
75
+
76
+ static VALUE stream_bitrate(VALUE self) {
77
+ AVStream * stream = get_stream(self);
78
+
79
+ rb_float_new(stream->codec->bit_rate);
80
+ }
81
+
82
+
83
+ static VALUE stream_position(VALUE self) {
84
+ AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
85
+ AVStream * stream = get_stream(self);
86
+ AVPacket decoding_packet;
87
+
88
+ av_init_packet(&decoding_packet);
89
+
90
+ do {
91
+ if(av_read_frame(format_context, &decoding_packet) < 0) {
92
+ rb_raise(rb_eRuntimeError, "error extracting packet");
93
+ }
94
+ } while(decoding_packet.stream_index != stream->index);
95
+
96
+ return rb_float_new(decoding_packet.pts * (double)av_q2d(stream->time_base));
97
+ }
98
+
99
+ static VALUE stream_init(VALUE self, VALUE media) {
100
+ //printf("Stream initialized\n");
101
+ rb_iv_set(self, "@media", media);
102
+ return self;
103
+ }
104
+
105
+ static VALUE alloc_stream(VALUE self) {
106
+ //printf("Stream allocating...\n");
107
+ AVStream * stream = av_new_stream(NULL, 0);
108
+ //printf("Stream wrapping...\n");
109
+ return Data_Wrap_Struct(rb_cStream, 0, 0, stream);
110
+ }
111
+
112
+ VALUE build_stream(AVStream *stream, VALUE rb_media) {
113
+ //printf("Stream building...\n");
114
+ VALUE rb_stream = Data_Wrap_Struct(rb_cStream, 0, 0, stream);
115
+ //printf("Stream wrapped\n");
116
+ return stream_init(rb_stream, rb_media);
117
+ }
118
+
119
+ void Init_stream() {
120
+ rb_cStream = rb_define_class_under(rb_mStreams, "Stream", rb_cObject);
121
+ rb_define_alloc_func(rb_cStream, alloc_stream);
122
+
123
+ rb_define_method(rb_cStream, "type", stream_type, 0);
124
+ rb_define_method(rb_cStream, "duration", stream_duration, 0);
125
+ rb_define_method(rb_cStream, "bitrate", stream_bitrate, 0);
126
+ rb_define_method(rb_cStream, "seek", stream_seek, 1);
127
+ rb_define_method(rb_cStream, "position", stream_position, 0);
128
+ }
@@ -0,0 +1,44 @@
1
+ #include "puremotion.h"
2
+
3
+ VALUE rb_cStreamCollection;
4
+ VALUE rb_mStreams;
5
+
6
+ static VALUE stream_collection_init(VALUE self) {
7
+
8
+ return self;
9
+
10
+ }
11
+
12
+ VALUE build_stream_collection(VALUE media) {
13
+
14
+
15
+ AVFormatContext *format_context = get_format_context(media);
16
+
17
+ VALUE rb_streams = rb_ary_new();
18
+
19
+ int i, stream_idx = 0;
20
+
21
+ for( i = 0; i < format_context->nb_streams; i++ ) {
22
+ AVStream *stream = format_context->streams[i];
23
+
24
+ VALUE rb_stream = Qnil;
25
+
26
+ if( stream->codec->codec_type == CODEC_TYPE_VIDEO ) rb_stream = build_video_stream( stream, media );
27
+ if( stream->codec->codec_type == CODEC_TYPE_AUDIO ) rb_stream = build_audio_stream( stream, media );
28
+
29
+ if( rb_stream != Qnil ) {
30
+ rb_ary_store(rb_streams, stream_idx, rb_stream);
31
+ stream_idx++;
32
+ }
33
+
34
+ }
35
+
36
+ return rb_streams;
37
+ }
38
+
39
+ void Init_stream_collection() {
40
+
41
+ rb_cStreamCollection = rb_define_class_under(rb_mStreams, "Collection", rb_cArray);
42
+ // rb_define_method(rb_cStreamCollection, "initialize", stream_collection_init, 1);
43
+
44
+ }
@@ -0,0 +1,81 @@
1
+ #include "utils.h"
2
+
3
+ AVFormatContext * get_format_context(VALUE self)
4
+ {
5
+ AVFormatContext * format_context = NULL;
6
+ Data_Get_Struct(self, AVFormatContext, format_context);
7
+ if (NULL == format_context) {
8
+ rb_fatal("FFMPEG internal error\n");
9
+ }
10
+ return format_context;
11
+ }
12
+
13
+ AVStream * get_stream(VALUE self)
14
+ {
15
+ AVStream * stream = NULL;
16
+ Data_Get_Struct(self, AVStream, stream);
17
+ if (NULL == stream) {
18
+ rb_fatal("FFMPEG internal error\n");
19
+ }
20
+ return stream;
21
+ }
22
+
23
+ AVCodecContext * get_codec_context(VALUE self)
24
+ {
25
+ AVCodecContext * codec_context = NULL;
26
+ Data_Get_Struct(self, AVCodecContext, codec_context);
27
+ if (NULL == codec_context) {
28
+ rb_fatal("FFMPEG internal error\n");
29
+ }
30
+ return codec_context;
31
+ }
32
+
33
+ AVFrame * get_frame(VALUE self)
34
+ {
35
+ AVFrame * frame = NULL;
36
+ Data_Get_Struct(self, AVFrame, frame);
37
+ if (NULL == frame) {
38
+ rb_fatal("FFMPEG internal error\n");
39
+ }
40
+ return frame;
41
+ }
42
+
43
+ VALUE rb_sym(const char *s) {
44
+ return rb_str_intern(rb_str_new2(s));
45
+ }
46
+
47
+ VALUE codec_type_id_to_sym(int codec_type)
48
+ {
49
+ VALUE type_sym;
50
+ switch(codec_type) {
51
+ case CODEC_TYPE_AUDIO:
52
+ type_sym = rb_sym("audio");
53
+ break;
54
+
55
+ case CODEC_TYPE_VIDEO:
56
+ type_sym = rb_sym("video");
57
+ break;
58
+
59
+ case CODEC_TYPE_SUBTITLE:
60
+ type_sym = rb_sym("subtitle");
61
+ break;
62
+
63
+ case CODEC_TYPE_DATA:
64
+ type_sym = rb_sym("data");
65
+ break;
66
+
67
+ case CODEC_TYPE_ATTACHMENT:
68
+ type_sym = rb_sym("attachment");
69
+ break;
70
+
71
+ case CODEC_TYPE_NB:
72
+ type_sym = rb_sym("nb");
73
+ break;
74
+
75
+ default:
76
+ type_sym = rb_sym("unknown");
77
+ break;
78
+ }
79
+
80
+ return type_sym;
81
+ }
@@ -0,0 +1,6 @@
1
+ #include "puremotion.h"
2
+
3
+ AVFormatContext * get_format_context(VALUE self);
4
+ AVStream * get_stream(VALUE self);
5
+ AVCodecContext * get_codec_context(VALUE self);
6
+ AVFrame * get_frame(VALUE self);
@@ -0,0 +1,141 @@
1
+ #include "puremotion.h"
2
+ #include "utils.h"
3
+
4
+ VALUE rb_cStream;
5
+ VALUE rb_cVideoStream;
6
+ VALUE rb_mStreams;
7
+
8
+ static VALUE stream_frame_rate(VALUE self) {
9
+ AVStream * stream = get_stream(self);
10
+ return(rb_float_new(av_q2d(stream->r_frame_rate)));
11
+ }
12
+
13
+ static int extract_next_frame(AVFormatContext * format_context, AVCodecContext * codec_context, int stream_index, AVFrame * frame, AVPacket * decoding_packet) {
14
+ // open codec to decode the video if needed
15
+ if (NULL == codec_context->codec) {
16
+ rb_fatal("codec should have already been opened");
17
+ }
18
+
19
+ uint8_t * databuffer;
20
+
21
+ int remaining = 0;
22
+ int decoded;
23
+ int frame_complete = 0;
24
+ int next;
25
+
26
+ while(!frame_complete &&
27
+ 0 == (next = next_packet_for_stream(format_context, stream_index, decoding_packet))) {
28
+ // setting parameters before processing decoding_packet data
29
+ remaining = decoding_packet->size;
30
+ databuffer = decoding_packet->data;
31
+
32
+ while(remaining > 0) {
33
+ decoded = avcodec_decode_video(codec_context, frame, &frame_complete,
34
+ databuffer, remaining);
35
+ remaining -= decoded;
36
+ // pointer seek forward
37
+ databuffer += decoded;
38
+ }
39
+ }
40
+
41
+ return next;
42
+ }
43
+
44
+ /*
45
+ * call-seq: grab => PureMotion::Frame
46
+ *
47
+ *
48
+ *
49
+ */
50
+
51
+ static VALUE stream_grab(VALUE self) {
52
+ AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
53
+ AVStream * stream = get_stream(self);
54
+
55
+ AVCodecContext * codec_context = stream->codec;
56
+
57
+ // open codec to decode the video if needed
58
+ if (!codec_context->codec) {
59
+ AVCodec * codec = avcodec_find_decoder(codec_context->codec_id);
60
+ if (!codec)
61
+ rb_raise(rb_eRuntimeError, "error codec not found");
62
+ if (avcodec_open(codec_context, codec) < 0)
63
+ rb_raise(rb_eRuntimeError, "error while opening codec : %s", codec->name);
64
+ }
65
+
66
+ VALUE rb_frame = rb_funcall(rb_const_get(rb_mPureMotion, rb_intern("Frame")),
67
+ rb_intern("new"), 3,
68
+ INT2NUM(codec_context->width),
69
+ INT2NUM(codec_context->height),
70
+ INT2NUM(codec_context->pix_fmt));
71
+
72
+ AVFrame * frame = get_frame(rb_frame);
73
+ avcodec_get_frame_defaults(frame);
74
+
75
+ AVPacket decoding_packet;
76
+ av_init_packet(&decoding_packet);
77
+
78
+ if (rb_block_given_p()) {
79
+ int ret;
80
+ do {
81
+ ret = extract_next_frame(format_context, stream->codec,
82
+ stream->index, frame, &decoding_packet);
83
+ rb_yield(
84
+ rb_ary_new3(
85
+ 3,
86
+ rb_frame,
87
+ rb_float_new(decoding_packet.pts * (double)av_q2d(stream->time_base)),
88
+ rb_float_new(decoding_packet.dts * (double)av_q2d(stream->time_base))
89
+ )
90
+ );
91
+ } while (ret == 0);
92
+ } else {
93
+ extract_next_frame(format_context, stream->codec,
94
+ stream->index, frame, &decoding_packet);
95
+ return rb_frame;
96
+ }
97
+
98
+ return self;
99
+ }
100
+
101
+ static VALUE stream_resolution(VALUE self, VALUE media) {
102
+ AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
103
+ AVStream * stream = get_stream(self);
104
+
105
+ VALUE width = INT2NUM(stream->codec->width);
106
+ VALUE height = INT2NUM(stream->codec->height);
107
+
108
+ VALUE res = rb_ary_new2(2);
109
+ rb_ary_store(res, 0, width);
110
+ rb_ary_store(res, 1, height);
111
+
112
+ return res;
113
+ }
114
+
115
+ static VALUE video_stream_init(VALUE self, VALUE media) {
116
+ //printf("Stream initialized\n");
117
+ rb_iv_set(self, "@media", media);
118
+ return self;
119
+ }
120
+
121
+ static VALUE alloc_video_stream(VALUE self) {
122
+ //printf("Stream allocating...\n");
123
+ AVStream * stream = av_new_stream(NULL, 0);
124
+ //printf("Stream wrapping...\n");
125
+ return Data_Wrap_Struct(rb_cVideoStream, 0, 0, stream);
126
+ }
127
+
128
+ VALUE build_video_stream(AVStream *stream, VALUE rb_media) {
129
+ //printf("Stream building...\n");
130
+ VALUE rb_stream = Data_Wrap_Struct(rb_cVideoStream, 0, 0, stream);
131
+ //printf("Stream wrapped\n");
132
+ return video_stream_init(rb_stream, rb_media);
133
+ }
134
+
135
+ void Init_video_stream() {
136
+ rb_cVideoStream = rb_define_class_under(rb_mStreams, "Video", rb_cStream);
137
+
138
+ rb_define_method(rb_cVideoStream, "resolution", stream_resolution, 0);
139
+ rb_define_method(rb_cVideoStream, "frame_rate", stream_frame_rate, 0);
140
+ rb_define_method(rb_cVideoStream, "grab", stream_grab, 0);
141
+ }