complexorganizations / mapping-united-com

❤️ Parking United: Space Awaits, Wherever You Are!
https://www.parking-united.com
Other
0 stars 2 forks source link

Using .srt files to efficiently locate and watch specific video segments #3

Closed Prajwal-Koirala closed 11 months ago

Prajwal-Koirala commented 1 year ago

Note: The .srt file contains the transcript of the dialogue and its timing information, which can be utilized to manually locate a specific 30-second segment of video footage within the media file. By referencing the timing cues in the .srt file, one can easily identify the precise starting and ending points of the desired segment and watch it on a video player or input it into an app. This method allows for greater accuracy and efficiency when searching for specific sections of video content, as it eliminates the need for tedious manual scrolling or searching.

Prajwal-Koirala commented 1 year ago

You can cut a video in Linux using frame count by using FFmpeg, a powerful and widely used open-source command-line tool for video and audio manipulation. Here are the steps:

  1. Install FFmpeg on your Linux system if it's not already installed. You can install it using your distribution's package manager or by downloading and compiling the source code from the official website.

  2. Open a terminal window and navigate to the directory containing the video file you want to cut.

  3. Determine the starting and ending frames of the segment you want to cut. You can do this using the frame rate and duration of the video. For example, if the video has a frame rate of 30 fps and you want to cut a segment from 10 seconds to 20 seconds, the starting frame will be 300 (10 seconds x 30 fps) and the ending frame will be 600 (20 seconds x 30 fps).

  4. Use the following FFmpeg command to cut the video segment:

    ffmpeg -i input.mp4 -ss START_FRAME -to END_FRAME -c:v copy -c:a copy output.mp4

    Replace START_FRAME and END_FRAME with the starting and ending frames you determined in step 3. Replace input.mp4 with the name of the input video file and output.mp4 with the name you want to give to the cut video file.

    The -c:v copy and -c:a copy options will copy the video and audio streams from the input file without re-encoding, which will result in faster processing and no loss in quality.

  5. Wait for FFmpeg to finish cutting the video segment. Depending on the length and complexity of the video, this may take some time.

  6. Once FFmpeg is done, you can find the cut video file in the same directory as the input file.

Prajwal-Koirala commented 1 year ago

If you have an .srt subtitle file for a video and want to watch a specific segment of the video without having to watch the entire thing, you can use the subtitles to identify the exact coordinates of the segment and then cut the video accordingly. Here are the steps:

  1. First, separate the .srt subtitle file from the video file if they are not already separate. This can be done by simply renaming the subtitle file to have the same name as the video file but with the .srt extension.

  2. Next, use a subtitle editor or a text editor to open the .srt file and locate the starting and ending times for the segment you want to watch. These times will be listed in the subtitle file in the format of hours, minutes, seconds, and milliseconds, like this: 00:01:23,456 --> 00:01:27,891.

  3. Convert the starting and ending times to frame numbers using the frame rate of the video. For example, if the video has a frame rate of 30 fps and the segment starts at 00:01:23,456, which is 83.456 seconds, the starting frame number would be 2504 (83.456 seconds x 30 fps). Similarly, if the segment ends at 00:01:27,891, which is 87.891 seconds, the ending frame number would be 2637 (87.891 seconds x 30 fps).

  4. Add a buffer of one minute (or however long you prefer) to the starting and ending frames to allow for some extra footage before and after the segment. For example, if you want a one-minute buffer, you would subtract 30 frames from the starting frame number and add 30 frames to the ending frame number.

  5. Use a video editing software like FFmpeg to cut the video based on the starting and ending frame numbers with the buffer. The command would look something like this:

    ffmpeg -i input.mp4 -ss START_FRAME -to END_FRAME -c:v copy -c:a copy output.mp4

    Replace START_FRAME and END_FRAME with the adjusted starting and ending frame numbers you determined in step 4. Replace input.mp4 with the name of the input video file and output.mp4 with the name you want to give to the cut video file.

    The -c:v copy and -c:a copy options will copy the video and audio streams from the input file without re-encoding, which will result in faster processing and no loss in quality.

  6. Wait for the video to be cut and then you can watch the specific segment with a one-minute buffer without having to watch the entire video.

Prajwal-Koirala commented 1 year ago

Yes, it's possible to parse an SRT file without using regular expressions. Here's an example code snippet that demonstrates how to do this:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type Subtitle struct {
    Number     int
    StartTime  string
    EndTime    string
    Text       string
}

func main() {
    // Open the SRT file for reading
    file, err := os.Open("example.srt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    // Use a scanner to read the file line by line
    scanner := bufio.NewScanner(file)

    var subs []Subtitle
    var sub Subtitle
    var inTextBlock bool

    for scanner.Scan() {
        line := scanner.Text()

        if !inTextBlock {
            // This is a new subtitle block
            if strings.TrimSpace(line) == "" {
                // Ignore blank lines
                continue
            }
            sub.Number, _ = strconv.Atoi(line)
            inTextBlock = true
        } else {
            // This is part of the subtitle text
            if strings.TrimSpace(line) == "" {
                // End of subtitle text block
                subs = append(subs, sub)
                sub = Subtitle{}
                inTextBlock = false
            } else {
                // This line is part of the subtitle text
                if sub.Text != "" {
                    sub.Text += "\n"
                }
                sub.Text += line
            }
        }
    }

    // Add the last subtitle to the list
    subs = append(subs, sub)

    // Print the list of subtitles
    for _, sub := range subs {
        fmt.Printf("%d\n%s --> %s\n%s\n\n", sub.Number, sub.StartTime, sub.EndTime, sub.Text)
    }
}

This code reads the SRT file line by line and uses a boolean variable inTextBlock to keep track of whether it's currently inside a subtitle text block or not. If it's not in a text block, it reads the subtitle number and sets inTextBlock to true. If it is in a text block, it reads the subtitle text until it encounters a blank line, at which point it adds the Subtitle struct to the list and resets the sub variable. Finally, it prints the list of subtitles.

This code works for the specific format of the SRT file you provided, where each subtitle block consists of a number, an empty line, the start and end times, another empty line, and the subtitle text. If your SRT file has a different format, you may need to adjust the code accordingly.

Prajwal-Koirala commented 1 year ago

Sure, you can use the standard packages bufio and strings to parse the file without using regular expressions. Here's an example:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

type FrameInfo struct {
    Index     int
    Data      string
    Timestamp string
    Metadata  map[string]string
}

func main() {
    fileContent := `...` // Paste the content of the file here
    reader := bufio.NewReader(strings.NewReader(fileContent))

    frames := []FrameInfo{}

    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            break
        }

        line = strings.TrimSpace(line)

        // Parse index
        var index int
        _, err = fmt.Sscanf(line, "%d", &index)
        if err != nil {
            continue
        }

        // Skip timestamp range line
        _, _ = reader.ReadString('\n')

        // Read data line
        dataLine, _ := reader.ReadString('\n')
        dataLine = strings.TrimSpace(strings.TrimPrefix(dataLine, "<font size=\"28\">"))

        // Read timestamp line
        timestampLine, _ := reader.ReadString('\n')
        timestampLine = strings.TrimSpace(timestampLine)

        // Read metadata line
        metadataLine, _ := reader.ReadString('\n')
        metadataLine = strings.TrimSpace(strings.TrimSuffix(metadataLine, "</font>"))

        metadata := map[string]string{}
        for _, kv := range strings.Split(metadataLine, "] [") {
            kv = strings.Trim(kv, "[]")
            parts := strings.SplitN(kv, ": ", 2)
            if len(parts) == 2 {
                metadata[parts[0]] = parts[1]
            }
        }

        frames = append(frames, FrameInfo{
            Index:     index,
            Data:      dataLine,
            Timestamp: timestampLine,
            Metadata:  metadata,
        })
    }

    for _, frame := range frames {
        fmt.Printf("Index: %d\nData: %s\nTimestamp: %s\n", frame.Index, frame.Data, frame.Timestamp)
        for k, v := range frame.Metadata {
            fmt.Printf("%s: %s\n", k, v)
        }
        fmt.Println()
    }
}

In this example, we use bufio.Reader to read lines from the input string, and then parse each line using basic string manipulation functions from the strings package. The parsed information is stored in a struct named FrameInfo, and the final parsed result is stored in a slice of FrameInfo.

Replace the fileContent variable with the content of the file you want to parse.

Prajwal-Koirala commented 1 year ago
1
00:00:00,000 --> 00:00:00,016
<font size="28">FrameCnt: 1, DiffTime: 16ms
2023-05-04 13:01:17.323
[iso: 120] [shutter: 1/2000.0] [fnum: 2.8] [ev: 0] [ct: 5347] [color_md : default] [focal_len: 24.00] [latitude: 40.73796] [longitude: -73.84101] [rel_alt: 67.200 abs_alt: 74.006] </font>

2
00:00:00,016 --> 00:00:00,032
<font size="28">FrameCnt: 2, DiffTime: 16ms
2023-05-04 13:01:17.337
[iso: 120] [shutter: 1/2000.0] [fnum: 2.8] [ev: 0] [ct: 5347] [color_md : default] [focal_len: 24.00] [latitude: 40.73796] [longitude: -73.84101] [rel_alt: 67.200 abs_alt: 74.006] </font>

3
00:00:00,032 --> 00:00:00,049
<font size="28">FrameCnt: 3, DiffTime: 17ms
2023-05-04 13:01:17.357
[iso: 120] [shutter: 1/2000.0] [fnum: 2.8] [ev: 0] [ct: 5347] [color_md : default] [focal_len: 24.00] [latitude: 40.73796] [longitude: -73.84101] [rel_alt: 67.200 abs_alt: 74.006] </font>

4
00:00:00,049 --> 00:00:00,066
<font size="28">FrameCnt: 4, DiffTime: 17ms
2023-05-04 13:01:17.370
[iso: 120] [shutter: 1/2000.0] [fnum: 2.8] [ev: 0] [ct: 5347] [color_md : default] [focal_len: 24.00] [latitude: 40.73796] [longitude: -73.84101] [rel_alt: 67.200 abs_alt: 74.006] </font>

5
00:00:00,066 --> 00:00:00,082
<font size="28">FrameCnt: 5, DiffTime: 16ms
2023-05-04 13:01:17.390
[iso: 120] [shutter: 1/2000.0] [fnum: 2.8] [ev: 0] [ct: 5347] [color_md : default] [focal_len: 24.00] [latitude: 40.73795] [longitude: -73.84101] [rel_alt: 67.200 abs_alt: 74.006] </font>