<commit_before>#include "puremotion.h"
#include "utils.h"

VALUE rb_cStream;
VALUE rb_cVideoStream;
VALUE rb_mStreams;

static int next_packet(AVFormatContext * format_context, AVPacket * packet)
{
    if(packet->data != NULL)
        av_free_packet(packet);

    if(av_read_frame(format_context, packet) < 0) {
        return -1;
    }

    return 0;
}

static int next_packet_for_stream(AVFormatContext * format_context, int stream_index, AVPacket * packet)
{
    int ret = 0;
    do {
        ret = next_packet(format_context, packet);
    } while(packet->stream_index != stream_index && ret == 0);

    return ret;
}

static VALUE stream_frame_rate(VALUE self) {
    AVStream * stream = get_stream(self);
    return(rb_float_new(av_q2d(stream->r_frame_rate)));
}

static int extract_next_frame(AVFormatContext * format_context, AVCodecContext * codec_context, int stream_index, AVFrame * frame, AVPacket * decoding_packet) {
    // open codec to decode the video if needed
    if (NULL == codec_context->codec) {
            rb_fatal("codec should have already been opened");
    }

    uint8_t * databuffer;

    int remaining = 0;
    int decoded;
    int frame_complete = 0;
    int next;

    while(!frame_complete &&
            0 == (next = next_packet_for_stream(format_context, stream_index, decoding_packet))) {
        // setting parameters before processing decoding_packet data
        remaining = decoding_packet->size;
        databuffer = decoding_packet->data;

        while(remaining > 0) {
            decoded = avcodec_decode_video(codec_context, frame, &frame_complete,
                databuffer, remaining);
            remaining -= decoded;
            // pointer seek forward
            databuffer += decoded;
        }
    }

    return next;
}

/*
 * call-seq: grab => PureMotion::Frame
 *
 *
 *
 */

static VALUE stream_grab(VALUE self) {
    AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
    AVStream * stream = get_stream(self);

    AVCodecContext * codec_context = stream->codec;

    // open codec to decode the video if needed
    if (!codec_context->codec) {
        AVCodec * codec = avcodec_find_decoder(codec_context->codec_id);
        if (!codec)
            rb_raise(rb_eRuntimeError, "error codec not found");
        if (avcodec_open(codec_context, codec) < 0)
            rb_raise(rb_eRuntimeError, "error while opening codec : %s", codec->name);
    }

    VALUE rb_frame = rb_funcall(rb_const_get(rb_mPureMotion, rb_intern("Frame")),
        rb_intern("new"), 3,
        INT2NUM(codec_context->width),
        INT2NUM(codec_context->height),
        INT2NUM(codec_context->pix_fmt));

    AVFrame * frame = get_frame(rb_frame);
    avcodec_get_frame_defaults(frame);

    AVPacket decoding_packet;
    av_init_packet(&decoding_packet);

    if (rb_block_given_p()) {
        int ret;
        do {
            ret = extract_next_frame(format_context, stream->codec,
                stream->index, frame, &decoding_packet);
            rb_yield(
                rb_ary_new3(
                    3,
                    rb_frame,
                    rb_float_new(decoding_packet.pts * (double)av_q2d(stream->time_base)),
                    rb_float_new(decoding_packet.dts * (double)av_q2d(stream->time_base))
                )
            );
        } while (ret == 0);
    } else {
        extract_next_frame(format_context, stream->codec,
            stream->index, frame, &decoding_packet);
        return rb_frame;
    }

    return self;
}

static VALUE stream_resolution(VALUE self, VALUE media) {
    AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
    AVStream * stream = get_stream(self);

    VALUE width = INT2NUM(stream->codec->width);
    VALUE height = INT2NUM(stream->codec->height);

    VALUE res = rb_ary_new2(2);
    rb_ary_store(res, 0, width);
    rb_ary_store(res, 1, height);

    return res;
}

static VALUE video_stream_init(VALUE self, VALUE media) {
    //printf("Stream initialized\n");
    rb_iv_set(self, "@media", media);
    return self;
}

static VALUE alloc_video_stream(VALUE self) {<commit_msg>Updated documentation for video streams<commit_after>#include "puremotion.h"
#include "utils.h"

VALUE rb_cStream;
VALUE rb_cVideoStream;
VALUE rb_mStreams;

static int next_packet(AVFormatContext * format_context, AVPacket * packet)
{
    if(packet->data != NULL)
        av_free_packet(packet);

    if(av_read_frame(format_context, packet) < 0) {
        return -1;
    }

    return 0;
}

static int next_packet_for_stream(AVFormatContext * format_context, int stream_index, AVPacket * packet)
{
    int ret = 0;
    do {
        ret = next_packet(format_context, packet);
    } while(packet->stream_index != stream_index && ret == 0);

    return ret;
}

/*
 * call-seq: frame_rate => Float
 *
 * Returns the video frame rate as a Float
 *
 * @return [Float] Framerate
 */
static VALUE stream_frame_rate(VALUE self) {
    AVStream * stream = get_stream(self);
    return(rb_float_new(av_q2d(stream->r_frame_rate)));
}

static int extract_next_frame(AVFormatContext * format_context, AVCodecContext * codec_context, int stream_index, AVFrame * frame, AVPacket * decoding_packet) {
    // open codec to decode the video if needed
    if (NULL == codec_context->codec) {
            rb_fatal("codec should have already been opened");
    }

    uint8_t * databuffer;

    int remaining = 0;
    int decoded;
    int frame_complete = 0;
    int next;

    while(!frame_complete &&
            0 == (next = next_packet_for_stream(format_context, stream_index, decoding_packet))) {
        // setting parameters before processing decoding_packet data
        remaining = decoding_packet->size;
        databuffer = decoding_packet->data;

        while(remaining > 0) {
            decoded = avcodec_decode_video(codec_context, frame, &frame_complete,
                databuffer, remaining);
            remaining -= decoded;
            // pointer seek forward
            databuffer += decoded;
        }
    }

    return next;
}

/*
 * call-seq: grab => PureMotion::Frame
 *
 * Grabs a single frame from the current position in the stream.
 *
 * Example Usage:
 *
 *      Media 'sample.wmv' do
 *
 *          if video? then
 *
 *              frame = video.seek(5).grab
 *
 *              # Resize, save
 *
 *          end
 *
 *      end
 *
 * @return [PureMotion::Frame]
 */

static VALUE stream_grab(VALUE self) {
    AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
    AVStream * stream = get_stream(self);

    AVCodecContext * codec_context = stream->codec;

    // open codec to decode the video if needed
    if (!codec_context->codec) {
        AVCodec * codec = avcodec_find_decoder(codec_context->codec_id);
        if (!codec)
            rb_raise(rb_eRuntimeError, "error codec not found");
        if (avcodec_open(codec_context, codec) < 0)
            rb_raise(rb_eRuntimeError, "error while opening codec : %s", codec->name);
    }

    VALUE rb_frame = rb_funcall(rb_const_get(rb_mPureMotion, rb_intern("Frame")),
        rb_intern("new"), 3,
        INT2NUM(codec_context->width),
        INT2NUM(codec_context->height),
        INT2NUM(codec_context->pix_fmt));

    AVFrame * frame = get_frame(rb_frame);
    avcodec_get_frame_defaults(frame);

    AVPacket decoding_packet;
    av_init_packet(&decoding_packet);

    if (rb_block_given_p()) {
        int ret;
        do {
            ret = extract_next_frame(format_context, stream->codec,
                stream->index, frame, &decoding_packet);
            rb_yield(
                rb_ary_new3(
                    3,
                    rb_frame,
                    rb_float_new(decoding_packet.pts * (double)av_q2d(stream->time_base)),
                    rb_float_new(decoding_packet.dts * (double)av_q2d(stream->time_base))
                )
            );
        } while (ret == 0);
    } else {
        extract_next_frame(format_context, stream->codec,
            stream->index, frame, &decoding_packet);
        return rb_frame;
    }

    return self;
}

/* call-seq: resolution => Array<Integer width, Integer height>
 *
 * Returns video frame resolution as [width, height] array
 *
 * @return [Array<Integer width, Integer height>]
 */
static VALUE stream_resolution(VALUE self, VALUE media) {
    AVFormatContext * format_context = get_format_context(rb_iv_get(self, "@media"));
    AVStream * stream = get_stream(self);

    VALUE width = INT2NUM(stream->codec->width);
    VALUE height = INT2NUM(stream->codec->height);

    VALUE res = rb_ary_new2(2);
    rb_ary_store(res, 0, width);
    rb_ary_store(res, 1, height);

    return res;
}

static VALUE video_stream_init(VALUE self, VALUE media) {
    //printf("Stream initialized\n");
    rb_iv_set(self, "@media", media);
    return self;
}

static VALUE alloc_video_stream(VALUE self) {
{'fraction_non_alphanumeric': 0.1082323912068192, 'fraction_numerical': 0.0061686855091969495, 'mean_word_length': 2.789630259243519, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6306669', 'n_tokens_mistral': 2869, 'n_tokens_neox': 2727, 'n_words': 608}