func (m *mp4Handler) RequestHandle(ctx context.Context, w http.ResponseWriter, r *http.Request) { // Handle only GET requests with ContentLength of 0 without a Range header if r.Method != "GET" || len(r.Header.Get("Range")) > 0 || r.ContentLength > 0 { m.next.RequestHandle(ctx, w, r) return } // parse the request var start, err = strconv.Atoi(r.URL.Query().Get(startKey)) if err != nil || 0 >= start { // that start is not ok m.next.RequestHandle(ctx, w, r) return } var startTime = time.Duration(start) * time.Second var newreq = copyRequest(r) removeQueryArgument(newreq.URL, startKey) var header = make(http.Header) var rr = &rangeReader{ ctx: ctx, req: copyRequest(newreq), location: m.loc, next: m.next, callback: func(frw *httputils.FlexibleResponseWriter) bool { if len(header) == 0 { httputils.CopyHeadersWithout(frw.Header(), header, skipHeaders...) } else { return frw.Header().Get("Last-Modified") == header.Get("Last-Modified") } return true }, } var video *mp4.MP4 video, err = mp4.Decode(rr) if err != nil { m.loc.Logger.Errorf("error from the mp4.Decode - %s", err) m.next.RequestHandle(ctx, w, r) return } if video == nil || video.Moov == nil { // missing something? m.next.RequestHandle(ctx, w, r) return } cl, err := clip.New(video, startTime, rr) if err != nil { m.loc.Logger.Errorf("error while clipping a video(%+v) - %s", video, err) m.next.RequestHandle(ctx, w, r) return } httputils.CopyHeaders(header, w.Header()) w.Header().Set("Content-Length", strconv.FormatUint(cl.Size(), 10)) size, err := cl.WriteTo(w) m.loc.Logger.Debugf("wrote %d", size) if err != nil { m.loc.Logger.Logf("error on writing the clip response - %s", err) } if uint64(size) != cl.Size() { m.loc.Logger.Debugf("handler.mp4[%p]: expected to write %d but wrote %d", m, cl.Size(), size) } }
func main() { go func() { fmt.Println(http.ListenAndServe(":6060", nil)) }() cmd := cli.App("mp4tool", "MP4 command line tool") cmd.Command("info", "Displays information about a media", func(cmd *cli.Cmd) { file := cmd.StringArg("FILE", "", "the file to display") cmd.Action = func() { rr := &fileRangeReader{fileName: *file} v, err := mp4.Decode(rr) if err != nil { fmt.Println(err) } v.Dump() } }) cmd.Command("clip", "Generates a clip", func(cmd *cli.Cmd) { start := cmd.IntOpt("s start", 0, "start time (sec)") src := cmd.StringArg("SRC", "", "the source file name") dst := cmd.StringArg("DST", "", "the destination file name") cmd.Action = func() { rr := &fileRangeReader{fileName: *src} v, err := mp4.Decode(rr) if err != nil { fmt.Println(err) return } out, err := os.Create(*dst) if err != nil { fmt.Println(err) return } defer closeWithPrintingError(out, "error on closing output file") clip, err := clip.New(v, time.Duration(*start)*time.Second, rr) if err != nil { fmt.Println(err) return } fmt.Scanln() size, err := clip.WriteTo(out) if err != nil { fmt.Println(err) } fmt.Println("wrote", size) } }) cmd.Command("copy", "Decodes a media and reencodes it to another file", func(cmd *cli.Cmd) { src := cmd.StringArg("SRC", "", "the source file name") dst := cmd.StringArg("DST", "", "the destination file name") cmd.Action = func() { rr := &fileRangeReader{fileName: *src} v, err := mp4.Decode(rr) if err != nil { fmt.Println(err) return } out, err := os.Create(*dst) if err != nil { fmt.Println(err) return } defer closeWithPrintingError(out, "error on closing output file") if err := v.Encode(out); err != nil { fmt.Println("error on encoding", err) } } }) if err := cmd.Run(os.Args); err != nil { fmt.Println("error form cmd.Run", err) } fmt.Println("press return to exit the program") fmt.Scanln() }