[рднрд╛рдЧ рез/реи] рдПрдлрдПрдлрдПрдордкреАрдИ рдФрд░ рдПрд╕рдбреАрдПрд▓ рдХреЗ рд▓рд┐рдП рдЧрд╛рдЗрдб рдпрд╛ резрежрежреж рд╕реЗ рдХрдо рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рдХреИрд╕реЗ рд▓рд┐рдЦреЗрдВ


рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреБрд░рд╛рдиреА рд╣реИ, рдореВрд▓ рд╕рд╛рдордЧреНрд░реА рдЕрднреА рднреА FFmpeg рдХреЗ рд╡рд┐рд╖рдп рдкрд░ рд╡рд┐рднрд┐рдиреНрди рдЙрдкрдпреЛрдЧреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд░рдгрд╛ рдХрд╛ рдПрдХ рд▓реЛрдХрдкреНрд░рд┐рдп рд╕реНрд░реЛрдд рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд░реВрд╕реА рдореЗрдВ рдореВрд▓ рдХрд╛ рдЕрднреА рднреА рдХреЛрдИ рдкреВрд░реНрдг рдЕрдиреБрд╡рд╛рдж рдирд╣реАрдВ рд╣реИред рд╣рдо рдХрд╖реНрдЯрдкреНрд░рдж рдЪреВрдХ рдХреЛ рд╕рд╣реА рдХрд░рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рдХрд╣реАрдВ рдмреЗрд╣рддрд░ рд╣реИред

рдФрд░ рдпрджреНрдпрдкрд┐ рд╣рдордиреЗ рдХреЛрд╢рд┐рд╢ рдХреА, рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рдЪрдордХрджрд╛рд░ рдкрд╛рда рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХреА рдХрдард┐рдирд╛рдЗрдпрд╛рдБ рдЕрдкрд░рд┐рд╣рд╛рд░реНрдп рд╣реИрдВ ред рдмрдЧреНрд╕ рдХреА рд░рд┐рдкреЛрд░реНрдЯ рдХрд░реЗрдВ (рдЕрдзрд┐рдорд╛рдирддрдГ рдирд┐рдЬреА рд╕рдВрджреЗрд╢реЛрдВ рдореЗрдВ) - рдПрдХ рд╕рд╛рде рд╣рдо рдмреЗрд╣рддрд░ рдХрд░реЗрдВрдЧреЗред

рд╡рд┐рд╖рдп - рд╕реВрдЪреА

EDISON рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ - рд╡реЗрдм-рд╡рд┐рдХрд╛рд╕
EDISON.

, C C++.

! ;-)

тЗС тЖТ


UPD: рдЗрд╕ рдЧрд╛рдЗрдб рдХреЛ рдлрд░рд╡рд░реА 2015 рддрдХ рдЕрдкрдбреЗрдЯ рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

FFmpeg рд╡реАрдбрд┐рдпреЛ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рд╕рд╛рдорд╛рдиреНрдп-рдЙрджреНрджреЗрд╢реНрдп рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╣рд╛рди рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИред рд╕рднреА рдбрд┐рдХреЛрдбрд┐рдВрдЧ, рдПрдиреНрдХреЛрдбрд┐рдВрдЧ, рдорд▓реНрдЯреАрдкреНрд▓реЗрдХреНрд╕рд┐рдВрдЧ рдФрд░ рдбреАрдореБрд▓реНрдЯрд┐рдкреНрд▓реЗрдХреНрд╕рд┐рдВрдЧ рдХрд╛ рдкреНрд░рджрд░реНрд╢рди рдХрд░рддреЗ рд╣реБрдП рдПрдлрдПрдлрдПрдордкреА рдкреВрд░реА рд╡реАрдбрд┐рдпреЛ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд░реВрдЯреАрди рдХрд╛ рдЦреНрдпрд╛рд▓ рд░рдЦрддрд╛ рд╣реИред рдЬреЛ рдореАрдбрд┐рдпрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЛ рдмрд╣реБрдд рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИред рд╕рдм рдХреБрдЫ рдХрд╛рдлреА рд╕рд░рд▓ рдФрд░ рддреНрд╡рд░рд┐рдд рд╣реИ, рд╕реА рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ, рдЖрдк рдЖрдЬ рдЙрдкрд▓рдмреНрдз рд▓рдЧрднрдЧ рдХрд┐рд╕реА рднреА рдХреЛрдбреЗрдХ рдХреЛ рдбрд┐рдХреЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдХреБрдЫ рдЕрдиреНрдп рдкреНрд░рд╛рд░реВрдкреЛрдВ рдХреЗ рд▓рд┐рдП рднреА рдПрдирдХреЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдХреЗрд╡рд▓ рдкрдХрдбрд╝ рдпрд╣ рд╣реИ рдХрд┐ рдкреНрд░рд▓реЗрдЦрди рдЬреНрдпрд╛рджрд╛рддрд░ рдЧрд╛рдпрдм рд╣реИред рдПрдХ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рд╣реИ ( рдореВрд▓ рдореЗрдВ, рдпрд╣рд╛рдВ рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рдЧреИрд░-рдореМрдЬреВрдж рд╡реЗрдм рдкреЗрдЬ рдХрд╛ рдПрдХ рд▓рд┐рдВрдХ рд╣реИ - рдиреЛрдЯ рдЕрдиреБрд╡рд╛рджрдХ), рдЬреЛ рдПрдлрдПрдлрдПрдордкреА рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рдФрд░ рдбреЙрдХреНрд╕ рдСрдХреНрд╕реАрдЬрди рдбреЙрдХреНрд╕ рдХреА рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдкреАрдврд╝реА рдХреЛ рдХрд╡рд░ рдХрд░рддрд╛ рд╣реИред рдФрд░ рдХреБрдЫ рдирд╣реАрдВред рдЗрд╕рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдбрд┐рдЬрд┐рдЯрд▓ рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП FFmpeg рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рджрд╕реНрддрд╛рд╡реЗрдЬ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдПрдХ рдкрд╛рдареНрдпрдкреБрд╕реНрддрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИред

рдПрдХ FFplay рдкреНрд░реЛрдЧреНрд░рд╛рдо рд╣реИ рдЬреЛ FFmpeg рдХреЗ рд╕рд╛рде рдЖрддрд╛ рд╣реИред рдпрд╣ рд╕рд░рд▓ рд╣реИ, рд╕реА рдореЗрдВ рд▓рд┐рдЦрд╛ рд╣реИ, рдПрдлрдПрдлрдПрдордкреАрдкреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдкреВрд░реНрдг рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред рдореЗрд░рд╛ рдкрд╣рд▓рд╛ рдкрд╛рда рдорд╛рд░реНрдЯрд┐рди рдмреЛрд╣реЗрдо рджреНрд╡рд╛рд░рд╛ рдореВрд▓ рдкрд╛рда рдХрд╛ рдПрдХ рдЕрджреНрдпрддрди рд╕рдВрд╕реНрдХрд░рдг рд╣реИ ( рдореВрд▓ рдореЗрдВ, рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рджреЛрд╖рдкреВрд░реНрдг рд╡реЗрдм рдкреЗрдЬ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ - рдПрдХ рдЕрдиреБрд╡рд╛рджрдХ рдХрд╛ рдиреЛрдЯ ) - рдореИрдВрдиреЗ рд╡рд╣рд╛рдВ рд╕реЗ рдХреБрдЫ рдЯреБрдХрдбрд╝реЗ рдЦреАрдВрдЪреЗред рдФрд░ рдЕрдкрдиреЗ рдкрд╛рдареЛрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдореЗрдВ рднреА рдореИрдВ ffplay.c рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдХрд╛рд░реНрдпрд╢реАрд▓ рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рдмрдирд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рджрд┐рдЦрд╛рдКрдВрдЧрд╛рдлреЗрдмреНрд░рд┐рд╕ рдмреЗрд▓рд╛рд░реНрдбред рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рда рдЕрдкрдиреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рд╡рд┐рдЪрд╛рд░ (рдпрд╛ рджреЛ рднреА) рдкреНрд░рд╕реНрддреБрдд рдХрд░реЗрдЧрд╛ред рдкреНрд░рддреНрдпреЗрдХ рдЕрдзреНрдпрд╛рдп рдПрдХ рд╕реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЖрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдЖрдк рдЕрдкрдиреЗ рджрдо рдкрд░ рд╕рдВрдХрд▓рд┐рдд рдФрд░ рдЪрд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╕реНрд░реЛрдд рдлрд╛рдЗрд▓реЗрдВ рдпрд╣ рдмрддрд╛рдПрдВрдЧреА рдХрд┐ рдпрд╣ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд╡реНрдпрдХреНрддрд┐рдЧрдд рднрд╛рдЧ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЗрд╕ рдЧрд╛рдЗрдб рдореЗрдВ рдХрд╡рд░ рдирд╣реАрдВ рдХрд┐рдП рдЧрдП рдорд╛рдореВрд▓реА рддрдХрдиреАрдХреА рд╡рд┐рд╡рд░рдг рднреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдЬрдм рд╣рдо рдХрд░ рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдХрд╛рдордХрд╛рдЬреА рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рд╣реЛрдЧрд╛ рдЬреЛ рдХреЛрдб рдХреА 1000 рд╕реЗ рдХрдо рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рд▓рд┐рдЦрд╛ рд╣реЛрдЧрд╛!

рдкреНрд▓реЗрдпрд░ рдмрдирд╛рддреЗ рд╕рдордп, рд╣рдо рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рдореАрдбрд┐рдпрд╛ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд╕рдбреАрдПрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред SDL рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдорд▓реНрдЯреАрдореАрдбрд┐рдпрд╛ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ MPEG рдкреНрд▓реЗрдмреИрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдо, рдПрдореБрд▓реЗрдЯрд░ рдФрд░ рдХрдИ рд╡реАрдбрд┐рдпреЛ рдЧреЗрдо рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рдЧрд╛рдЗрдб рд╕реЗ рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЕрдкрдиреЗ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рдПрд╕рдбреАрдПрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдФрд░ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдпрд╣ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдЕрдЪреНрдЫреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдЕрдиреБрднрд╡ рд╡рд╛рд▓реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИред рдмрд╣реБрдд рдХрдо рд╕реЗ рдХрдо, рдЖрдкрдХреЛ рд╕реА рдЬрд╛рдирдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ, рдФрд░ рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреА рд╕рдордЭ рднреА рд╣реИ рдЬреИрд╕реЗ рдХрд┐ рдХрддрд╛рд░, рдореНрдпреВрдЯреЗрдХреНрд╕, рдЖрджрд┐ред рдорд▓реНрдЯреАрдореАрдбрд┐рдпрд╛ рдХреА рдХреБрдЫ рд╕рдордЭ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП; рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╡реЗрд╡рдлреЙрд░реНрдо рдФрд░ рдЬреИрд╕реА рдЪреАрдЬреЗрдВред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЗрди рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЧреБрд░реБ рд╣реЛрдирд╛ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдкрд╛рда рдХреЗ рджреМрд░рд╛рди рдХрдИ рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЛ рд╕рдордЭрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдХреГрдкрдпрд╛ рдореБрдЭреЗ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢, рдкреНрд░рд╢реНрди, рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ, рд╡рд┐рдЪрд╛рд░, рд╕реБрд╡рд┐рдзрд╛рдПрдБ, рдЬреЛ рднреА рд╣реЛ, Dranger рдбреЙрдЧреА рдЬреАрдореЗрд▓ рдбреЙрдЯ рдХреЙрдо рдкрд░ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рддрдВрддреНрд░ рдорд╣рд╕реВрд╕ рдХрд░реЗрдВред








рдХрдВрдкрдиреА EDISON рдХреЗ рдмреНрд▓реЙрдЧ рдкрд░ рднреА рдкрдврд╝реЗрдВ :


рдПрдлрдПрдлрдПрдордкреАрдПрдл рд▓рд┐рдмрд╛рд╡ рдореИрдиреБрдЕрд▓






рдкрд╛рда 1: рдмрдирд╛рдирд╛ Screencaps тЖР тЗС тЖТ


рдкреВрд░реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ: tutorial01.c
// tutorial01.c
// Code based on a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
// With updates from https://github.com/chelyaev/ffmpeg-tutorial
// Updates tested on:
// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101 
// on GCC 4.7.2 in Debian February 2015

// A small sample program that shows how to use libavformat and libavcodec to
// read video from a file.
//
// Use
//
// gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lswscale -lz
//
// to build (assuming libavformat and libavcodec are correctly installed
// your system).
//
// Run using
//
// tutorial01 myvideofile.mpg
//
// to write the first five frames from "myvideofile.mpg" to disk in PPM
// format.

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <stdio.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  FILE *pFile;
  char szFilename[32];
  int  y;
  
  // Open file
  sprintf(szFilename, "frame%d.ppm", iFrame);
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;
  
  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  
  // Write pixel data
  for(y=0; y<height; y++)
    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  
  // Close file
  fclose(pFile);
}

int main(int argc, char *argv[]) {
  // Initalizing these to NULL prevents segfaults!
  AVFormatContext   *pFormatCtx = NULL;
  int               i, videoStream;
  AVCodecContext    *pCodecCtxOrig = NULL;
  AVCodecContext    *pCodecCtx = NULL;
  AVCodec           *pCodec = NULL;
  AVFrame           *pFrame = NULL;
  AVFrame           *pFrameRGB = NULL;
  AVPacket          packet;
  int               frameFinished;
  int               numBytes;
  uint8_t           *buffer = NULL;
  struct SwsContext *sws_ctx = NULL;

  if(argc < 2) {
    printf("Please provide a movie file\n");
    return -1;
  }
  // Register all formats and codecs
  av_register_all();
  
  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
  
  // Get a pointer to the codec context for the video stream
  pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }
  // Copy context
  pCodecCtx = avcodec_alloc_context3(pCodec);
  if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }

  // Open codec
  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=av_frame_alloc();
  
  // Allocate an AVFrame structure
  pFrameRGB=av_frame_alloc();
  if(pFrameRGB==NULL)
    return -1;

  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
			      pCodecCtx->height);
  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
  
  // Assign appropriate parts of buffer to image planes in pFrameRGB
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
		 pCodecCtx->width, pCodecCtx->height);
  
  // initialize SWS context for software scaling
  sws_ctx = sws_getContext(pCodecCtx->width,
			   pCodecCtx->height,
			   pCodecCtx->pix_fmt,
			   pCodecCtx->width,
			   pCodecCtx->height,
			   PIX_FMT_RGB24,
			   SWS_BILINEAR,
			   NULL,
			   NULL,
			   NULL
			   );

  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) {
      // Decode video frame
      avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
      
      // Did we get a video frame?
      if(frameFinished) {
	// Convert the image from its native format to RGB
	sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
		  pFrame->linesize, 0, pCodecCtx->height,
		  pFrameRGB->data, pFrameRGB->linesize);
	
	// Save the frame to disk
	if(++i<=5)
	  SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, 
		    i);
      }
    }
    
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
  }
  
  // Free the RGB image
  av_free(buffer);
  av_frame_free(&pFrameRGB);
  
  // Free the YUV frame
  av_frame_free(&pFrame);
  
  // Close the codecs
  avcodec_close(pCodecCtx);
  avcodec_close(pCodecCtxOrig);

  // Close the video file
  avformat_close_input(&pFormatCtx);
  
  return 0;
}

рдЕрд╡рд▓реЛрдХрди


рдореВрд╡реА рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдХрдИ рдореБрдЦреНрдп рдШрдЯрдХ рд╣реЛрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╣реА рдПрдХ рдХрдВрдЯреЗрдирд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ , рдФрд░ рдХрдВрдЯреЗрдирд░ рдХрд╛ рдкреНрд░рдХрд╛рд░ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдбреЗрдЯрд╛ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдХрдВрдЯреЗрдирд░реЛрдВ рдХреЗ рдЙрджрд╛рд╣рд░рдг AVI рдФрд░ рдХреНрд╡рд┐рдХрдЯрд╛рдЗрдо рд╣реИрдВ ред рдЖрдЧреЗ, рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдХрдИ рдереНрд░реЗрдбреНрд╕ рд╣реИрдВ; рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдЖрдорддреМрд░ рдкрд░ рдПрдХ рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдФрд░ рдПрдХ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд╣реИ ред ("рдЯреНрд╡реАрдЯ" "рдЯрд╛рдЗрдорд▓рд╛рдЗрди рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЙрдкрд▓рдмреНрдз рдбреЗрдЯрд╛ рдЖрдЗрдЯрдореНрд╕ рдХрд╛ рдПрдХ рдХреНрд░рдо" рдХреЗ рд▓рд┐рдП рдПрдХ рдордЬрд╝реЗрджрд╛рд░ рд╢рдмреНрдж рд╣реИред) рдПрдХ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдбреЗрдЯрд╛ рдЖрдЗрдЯрдореНрд╕ рдХреЛ рдлрд╝реНрд░реЗрдо рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдкреНрд░рддреНрдпреЗрдХ рдзрд╛рд░рд╛ рдПрдХ рдпрд╛ рджреВрд╕рд░реЗ рдкреНрд░рдХрд╛рд░ рдХреЗ рдХреЛрдбреЗрдХ рджреНрд╡рд╛рд░рд╛ рдПрдиреНрдХреЛрдб рдХреА рдЧрдИ рд╣реИ ред рдХреЛрдбреЗрдХ рдХреИрд╕реЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдбреЗрдЯрд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП diruyutsya рдФрд░ рджрд┐рд╕рдореНрдмрд░рдЕрдВрдХреЗрдХреНрд╖рд┐рдд - рдЗрд╕рд▓рд┐рдП рдХреЛрдбреЗрдХ рдХрд╛ рдирд╛рдоред рдХреЛрдбреЗрдХреНрд╕ рдХреЗ рдЙрджрд╛рд╣рд░рдг DivX рдФрд░ MP3 рд╣реИрдВред рдкреИрдХреЗрдЯ рддрдм рдзрд╛рд░рд╛ рд╕реЗ рдкрдврд╝реЗ рдЬрд╛рддреЗ рд╣реИрдВред рдкреИрдХреЗрдЯ рдбреЗрдЯрд╛ рдХреЗ рдЯреБрдХрдбрд╝реЗ рд╣реЛрддреЗ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдбреЗрдЯрд╛ рдХреЗ рдмрд┐рдЯреНрд╕ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдХрдЪреНрдЪреЗ рдлрд╝реНрд░реЗрдореЛрдВ рдореЗрдВ рдбрд┐рдХреЛрдб рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЕрдВрдд рдореЗрдВ рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рд╣реЗрд░рдлреЗрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рдкреИрдХреЗрдЯ рдореЗрдВ рдкреВрд░реНрдг рдлрд╝реНрд░реЗрдо (рдпрд╛ рдпрджрд┐ рдСрдбрд┐рдпреЛ рд╣реИ рддреЛ рдХрдИ рдлрд╝реНрд░реЗрдо рд╣реИрдВ)ред

рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рд╕рдмрд╕реЗ рдмреБрдирд┐рдпрд╛рджреА рд╕реНрддрд░ рдкрд░ рднреА рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ:

10 OPEN video_stream FROM video.avi
20 READ packet FROM video_stream INTO frame
30 IF frame NOT COMPLETE GOTO 20
40 DO SOMETHING WITH frame
50 GOTO 20

FFmpeg рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдорд▓реНрдЯреАрдореАрдбрд┐рдпрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рд▓рдЧрднрдЧ рдЙрддрдирд╛ рд╣реА рд╕рд░рд▓ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдХреБрдЫ рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдореЗрдВ "MAKE [...]" рдЪрд░рдг рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдореЗрдВ, рд╣рдо рдлрд╛рдЗрд▓ рдХреЛ рдУрдкрди рдХрд░реЗрдВрдЧреЗ, рдЗрд╕рдХреЗ рдЕрдВрджрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВрдЧреЗ, рдФрд░ рд╣рдорд╛рд░реА "MAKE [...]" рдкреАрдкреАрдПрдо рдлрд╛рдЗрд▓ рдХреЛ рдлреНрд░реЗрдо рд▓рд┐рдЦреЗрдВрдЧреЗред

рдЦреБрд▓реА рдлрд╛рдЗрд▓


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдлрд╝рд╛рдЗрд▓ рдЦреЛрд▓рддреЗ рд╣реА рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИред FFmpeg рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдкрд╣рд▓реЗ рд╡рд╛рдВрдЫрд┐рдд рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <ffmpeg/swscale.h>
...
int main(int argc, charg *argv[]) {
av_register_all();

рдпрд╣ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдореЗрдВ рд╕рднреА рдЙрдкрд▓рдмреНрдз рдлрд╝рд╛рдЗрд▓ рд╕реНрд╡рд░реВрдкреЛрдВ рдФрд░ рдХреЛрдбреЗрдХреНрд╕ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдкреНрд░рд╛рд░реВрдк / рдХреЛрдбреЗрдХ рдХреЗ рд╕рд╛рде рдлрд╝рд╛рдЗрд▓ рдЦреЛрд▓рдиреЗ рдкрд░ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдкрдХреЛ av_register_all () рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ , рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕реЗ рдпрд╣рд╛рдВ рдореБрдЦреНрдп () рдореЗрдВ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ, рддреЛ рдЖрдк рдХреЗрд╡рд▓ рдЪрдпрдирд╛рддреНрдордХ рдлрд╝рд╛рдЗрд▓ рд╕реНрд╡рд░реВрдкреЛрдВ рдФрд░ рдХреЛрдбреЗрдХреНрд╕ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЖрдорддреМрд░ рдкрд░ рдРрд╕рд╛ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░рдг рдирд╣реАрдВ рд╣реИред

рдЕрдм рдлрд╝рд╛рдЗрд▓ рдЦреЛрд▓реЗрдВ:

AVFormatContext *pFormatCtx = NULL;

// Open video file
if(avformat_open_input(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
  return -1; // Couldn't open file

рдкрд╣рд▓реЗ рддрд░реНрдХ рд╕реЗ рдлрд╝рд╛рдЗрд▓ рдирд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдлрд╝рд╛рдЗрд▓ рд╣реЗрдбрд░ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ AVFormatContext рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдлрд╝рд╛рдЗрд▓ рдкреНрд░рд╛рд░реВрдк рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдерд╛ред рдЕрдВрддрд┐рдо рддреАрди рддрд░реНрдХ рдлрд╝рд╛рдЗрд▓ рдкреНрд░рд╛рд░реВрдк, рдмрдлрд░ рдЖрдХрд╛рд░ рдФрд░ рдкреНрд░рд╛рд░реВрдк рдкреИрд░рд╛рдореАрдЯрд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЙрдиреНрд╣реЗрдВ NULL рдпрд╛ 0 рдкрд░ рд╕реЗрдЯ рдХрд░рдХреЗ, libavformat рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╕рдм рдХреБрдЫ рдкрддрд╛ рд▓рдЧрд╛ рд▓реЗрдЧрд╛ред

рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХреЗрд╡рд▓ рд╣реЗрдбрд░ рдХреЛ рджреЗрдЦрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЕрдм рд╣рдореЗрдВ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрдЯреНрд░реАрдо рдЬрд╛рдирдХрд╛рд░реА рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

// Retrieve stream information
if(avformat_find_stream_info(pFormatCtx, NULL)<0)
  return -1; // Couldn't find stream information

рдпрд╣ рдлрд╝рдВрдХреНрд╢рди pFormatCtx -> рдзрд╛рд░рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╡реИрдз рдбреЗрдЯрд╛ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИ ред рд╣рдо рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдбрд┐рдмрдЧрд┐рдВрдЧ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрддреЗ рд╣реИрдВ, рд╣рдореЗрдВ рджрд┐рдЦрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдЕрдВрджрд░ рдХреНрдпрд╛ рд╣реИ:

// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, argv[1], 0);

рдЕрдм pFormatCtx -> рдзрд╛рд░рд╛рдПрдВ рдХреЗрд╡рд▓ pFormatCtx -> nb_streams рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рд╕рдВрдХреЗрдд рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИрдВ ред рдЬрдм рддрдХ рд╣рдо рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдирд╣реАрдВ рдЦреЛрдЬ рд▓реЗрддреЗ, рд╣рдо рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рдПрдВрдЧреЗ:

int i;
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext *pCodecCtx = NULL;

// Find the first video stream
videoStream=-1;
for(i=0; i<pFormatCtx->nb_streams; i++)
  if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
    videoStream=i;
    break;
  }
if(videoStream==-1)
  return -1; // Didn't find a video stream

// Get a pointer to the codec context for the video stream
pCodecCtx=pFormatCtx->streams[videoStream]->codec;

рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдХреЛрдбреЗрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА " рдХреЛрдбреЗрдХ рд╕рдВрджрд░реНрдн " рдирд╛рдордХ рдПрдХ рд╕реНрдерд╛рди рдкрд░ рд╕реНрдерд┐рдд рд╣реИ ред рдЗрд╕рдореЗрдВ рдХреЛрдбреЗрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рд╣реИ рдЬреЛ рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕рдХрд╛ рдПрдХ рд╕рдВрдХреЗрддрдХ рд╣реИред рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдЕрднреА рднреА рдЕрд╕рд▓реА рдХреЛрдбреЗрдХ рдвреВрдВрдврдирд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдЦреЛрд▓рдирд╛ рд╣реИ:

AVCodec *pCodec = NULL;

// Find the decoder for the video stream
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL) {
  fprintf(stderr, "Unsupported codec!\n");
  return -1; // Codec not found
}
// Copy context
pCodecCtx = avcodec_alloc_context3(pCodec);
if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
  fprintf(stderr, "Couldn't copy codec context");
  return -1; // Error copying codec context
}
// Open codec
if(avcodec_open2(pCodecCtx, pCodec)<0)
  return -1; // Could not open codec

рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк рд╕реАрдзреЗ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд╕реЗ AVCodecContext рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ! рдЗрд╕рд▓рд┐рдП, рдЖрдкрдХреЛ рд╕рдВрджрд░реНрдн рдХреЛ рдХрд┐рд╕реА рдирдП рд╕реНрдерд╛рди рдкрд░ (рдмреЗрд╢рдХ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж) рдХреЙрдкреА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП vcodec_copy_context () рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ ред

рдЖрдзрд╛рд░ рд╕рд╛рдордЧреНрд░реА рднрдВрдбрд╛рд░рдг


рдЕрдм рд╣рдореЗрдВ рдлреНрд░реЗрдо рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрдЧрд╣ рдЪрд╛рд╣рд┐рдП:

AVFrame *pFrame = NULL;

// Allocate video frame
pFrame=av_frame_alloc();

рдЪреВрдВрдХрд┐ рд╣рдо рдкреАрдкреАрдПрдо рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ 24-рдмрд┐рдЯ рдЖрд░рдЬреАрдмреА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЕрдкрдиреЗ рдлреНрд░реЗрдо рдХреЛ рдЕрдкрдиреЗ рдкреНрд░рд╛рд░реВрдк рд╕реЗ рдЖрд░рдЬреАрдмреА рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред FFmpeg рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдХрд░реЗрдЧрд╛ред рдЕрдзрд┐рдХрд╛рдВрд╢ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ (рдЗрд╕ рдПрдХ рд╕рд╣рд┐рдд) рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкреНрд░рд╛рд░рдВрдн рдлреНрд░реЗрдо рдХреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП рдПрдХ рдлреНрд░реЗрдо рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ:

// Allocate an AVFrame structure
pFrameRGB=av_frame_alloc();
if(pFrameRGB==NULL)
  return -1;

рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рд╣рдордиреЗ рдлреНрд░реЗрдо рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рд╣реИ, рдлрд┐рд░ рднреА рд╣рдореЗрдВ рдЗрд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддреЗ рд╕рдордп рдХрдЪреНрдЪреЗ рдбреЗрдЯрд╛ рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрдЧрд╣ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд╣рдо рд╕рд╣реА рдЖрдХрд╛рд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рд╕реНрдерд╛рди рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП avpicture_get_size рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ :

uint8_t *buffer = NULL;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
                            pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

av_malloc FFmpeg рд╕реЗ C-function malloc рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИ , рдЬреЛ Malloc рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЖрд╡рд░рдг рд╣реИ рдЬреЛ рдореЗрдореЛрд░реА рдПрдбреНрд░реЗрд╕, рдЖрджрд┐ рдХреЗ рд╕рдВрд░реЗрдЦрдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рд╡реИрд╕реЗ, рдпрд╣ рдореЗрдореЛрд░реА рд▓реАрдХ, рдбрдмрд▓ рдлреНрд░реАрдЬрд┐рдВрдЧ рдпрд╛ рдЕрдиреНрдп рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдЦрд┐рд▓рд╛рдл рд░рдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдореЙрд▓реЛрдХ рдХреЗ рд╕рд╛рде рд╣реЛрддреА рд╣реИрдВ ред

рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдирдП рдЖрд╡рдВрдЯрд┐рдд рдмрдлрд░ рдХреЗ рд╕рд╛рде рдлреНрд░реЗрдо рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП avpicture_fill рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ ред рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ AVPicture : AVPicture рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдПрдХ рд╕рдмрд╕реЗрдЯ рд╣реИ AVFrame рд╕рдВрд░рдЪрдирд╛ - рдХреА рд╢реБрд░реБрдЖрдд AVFrame рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдХреЗ рд╕рдорд╛рди AVPicture рд╕рдВрд░рдЪрдирд╛ ред

// Assign appropriate parts of buffer to image planes in pFrameRGB
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
                pCodecCtx->width, pCodecCtx->height);

рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдлрд┐рдирд┐рд╢ рд▓рд╛рдЗрди рдкрд░ рд╣реИрдВ! рдЕрдм рд╣рдо рд╕реНрдЯреНрд░реАрдо рд╕реЗ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ!

рдбреЗрдЯрд╛ рдкрдврд╝рдирд╛


рдЕрдм, рд╕рдВрдкреВрд░реНрдг рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЕрдЧрд▓реЗ рдкреИрдХреЗрдЬ рдХреЛ рдкрдврд╝рддреЗ рд╣реИрдВ, рдЗрд╕реЗ рдЕрдкрдиреЗ рдлреНрд░реЗрдо рдореЗрдВ рдбрд┐рдХреНрд░рд┐рдкреНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЬреИрд╕реЗ рд╣реА рдбрд┐рдХреНрд░рд┐рдкреНрд╢рди рдкреВрд░рд╛ рд╣реЛрддрд╛ рд╣реИ, рдлреНрд░реЗрдо рдХреЛ рдХрдиреНрд╡рд░реНрдЯ рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рд╕рд╣реЗрдЬреЗрдВ:

struct SwsContext *sws_ctx = NULL;
int frameFinished;
AVPacket packet;
// initialize SWS context for software scaling
sws_ctx = sws_getContext(pCodecCtx->width,
    pCodecCtx->height,
    pCodecCtx->pix_fmt,
    pCodecCtx->width,
    pCodecCtx->height,
    PIX_FMT_RGB24,
    SWS_BILINEAR,
    NULL,
    NULL,
    NULL
    );

i=0;
while(av_read_frame(pFormatCtx, &packet)>=0) {
  // Is this a packet from the video stream?
  if(packet.stream_index==videoStream) {
	// Decode video frame
    avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
    
    // Did we get a video frame?
    if(frameFinished) {
    // Convert the image from its native format to RGB
        sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
		  pFrame->linesize, 0, pCodecCtx->height,
		  pFrameRGB->data, pFrameRGB->linesize);
	
        // Save the frame to disk
        if(++i<=5)
          SaveFrame(pFrameRGB, pCodecCtx->width, 
                    pCodecCtx->height, i);
    }
  }
    
  // Free the packet that was allocated by av_read_frame
  av_free_packet(&packet);
}

рдХреБрдЫ рднреА рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИ: av_read_frame () рдкреИрдХреЗрдЬ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ AVPacket рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдмрдЪрд╛рддрд╛ рд╣реИ ред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдо рдХреЗрд╡рд▓ рдкреИрдХреЗрдЬ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рд╡рд┐рддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ - FFmpeg рд╣рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рдбреЗрдЯрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ packet.data рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ ред рдпрд╣ рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж av_free_packet () рдХреЛ рдореБрдХреНрдд рдХрд░рддрд╛ рд╣реИ ред avcodec_decode_video () рдкреИрдХреЗрдЯ рдХреЛ рдлрд╝реНрд░реЗрдо рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкреИрдХреЗрдЯ рдХреЛ рдбрд┐рдХреЛрдб рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП avcodec_decode_video () рд╕реЗрдЯ рдлреНрд░реЗрдо рддрдм рд╣реЛрддрд╛ рд╣реИ рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрдЧрд▓рд╛ рдлреНрд░реЗрдо рд╣реЛрддрд╛ рд╣реИред рдЕрдВрдд рдореЗрдВ, рд╣рдо рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдкреНрд░рд╛рд░реВрдк ( pCodecCtx -> ) рд╕реЗ рдХрдирд╡рд░реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП sws_scale () рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВRGB рдореЗрдВ Pix_fmt )ред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рдЖрдк рдПрдХ рдбрд╛рд▓ рд╕рдХрддрд╛ AVFrame рдПрдХ рд╕реВрдЪрдХ AVPicture рд╕реВрдЪрдХред рдЕрдВрдд рдореЗрдВ, рд╣рдо рдЕрдкрдиреЗ SaveFrame рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдлреНрд░реЗрдо, рдКрдВрдЪрд╛рдИ рдФрд░ рдЪреМрдбрд╝рд╛рдИ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред

рдкреИрдХреЗрдЬ рдХреА рдмрд╛рдд рд╣реЛ рд░рд╣реА рд╣реИред рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдПрдХ рдкреИрдХреЗрдЯ рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдлреНрд░реЗрдо рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рд╕рд╛рде рдЕрдиреНрдп рдбреЗрдЯрд╛ рдмрд┐рдЯреНрд╕ рднреАред рд╣рд╛рд▓рд╛рдБрдХрд┐, FFmpeg рдкрд╛рд░реНрд╕рд░ рдЗрд╕ рдмрд╛рдд рдХреА рдЧрд╛рд░рдВрдЯреА рджреЗрддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдЬреЛ рдкреИрдХреЗрдЯ рдорд┐рд▓рддреЗ рд╣реИрдВ, рд╡реЗ рдпрд╛ рддреЛ рдПрдХ рдкреВрд░реНрдг рдлреНрд░реЗрдо рдпрд╛ рдХрдИ рдлреНрд░реЗрдо рд╣реЛрддреЗ рд╣реИрдВред

рдЕрдм рдЬреЛ рдХреБрдЫ рдХрд░рдирд╛ рдмрд╛рдХреА рд╣реИ, рд╡рд╣ рд╣реИрдЖрд░рдЬреАрдмреА рдЬрд╛рдирдХрд╛рд░реА рдХреЛ PPM рдлрд╛рдЗрд▓ рдореЗрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП SaveFrame рдлрд╝рдВрдХреНрд╢рдирдХрд╛рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред рдпрджреНрдпрдкрд┐ рд╣рдо рдкреАрдкреАрдПрдо рдкреНрд░рд╛рд░реВрдк рдХреЗ рд╕рд╛рде рд╣реА рд╕рддрд╣реА рд░реВрдк рд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВ; рдореЗрд░рд╛ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдХрд░реЛ, рдпрд╣рд╛рдБ рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  FILE *pFile;
  char szFilename[32];
  int  y;
  
  // Open file
  sprintf(szFilename, "frame%d.ppm", iFrame);
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;
  
  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  
  // Write pixel data
  for(y=0; y<height; y++)
    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  
  // Close file
  fclose(pFile);
}

рд╣рдо рдПрдХ рдорд╛рдирдХ рдлрд╝рд╛рдЗрд▓ рдУрдкрди рдЖрджрд┐ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ RGB рдбреЗрдЯрд╛ рд░рд┐рдХреЙрд░реНрдб рдХрд░рддреЗ рд╣реИрдВред рдлрд╝рд╛рдЗрд▓ рдХреЛ рд▓рд╛рдЗрди рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИред рдПрдХ PPM рдлрд╛рдЗрд▓ рдмрд╕ рдПрдХ рдлрд╛рдЗрд▓ рд╣реИ рдЬрд┐рд╕рдореЗрдВ RGB рд╕реВрдЪрдирд╛ рдХреЛ рдПрдХ рд▓рдВрдмреА рд▓рд╛рдЗрди рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдк HTML рдХреЗ рд░рдВрдЧреЛрдВ рдХреЛ рдЬрд╛рдирддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдкреНрд░рддреНрдпреЗрдХ рдкрд┐рдХреНрд╕реЗрд▓ рдХреЗ рд░рдВрдЧреЛрдВ рдХреЛ рдкрд╣рд▓реЗ рдЫреЛрд░ рд╕реЗ рдЕрдВрддрд┐рдо рдЫреЛрд░ рддрдХ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рдиреЗ рдЬреИрд╕рд╛ рд╣реЛрдЧрд╛, рдЬреИрд╕реЗ рдХрд┐ # ff0000 # ff0000 .... , рд▓рд╛рд▓ рд╕реНрдХреНрд░реАрди рдХреЗ рд▓рд┐рдПред (рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рджреНрд╡рд┐рдЖрдзрд╛рд░реА рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдФрд░ рдПрдХ рд╡рд┐рднрд╛рдЬрдХ рдХреЗ рдмрд┐рдирд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЖрдк рд╡рд┐рдЪрд╛рд░ рдХреЛ рдкрдХрдбрд╝рддреЗ рд╣реИрдВред) рд╢реАрд░реНрд╖рдХ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЫрд╡рд┐ рдХрд┐рддрдиреА рдЪреМрдбрд╝реА рдФрд░ рдЙрдЪреНрдЪ рд╣реИ, рд╕рд╛рде рд╣реА рд╕рд╛рде рдЖрд░рдЬреАрдмреА рдореВрд▓реНрдпреЛрдВ рдХрд╛ рдЕрдзрд┐рдХрддрдо рдЖрдХрд╛рд░ рднреА рд╣реИред

рдЕрдм рд╣рдорд╛рд░реЗ рдореБрдЦреНрдп () рдлрд╝рдВрдХреНрд╢рди рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ ред рдЬреИрд╕реЗ рд╣реА рд╣рдо рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд╕реЗ рдкрдврд╝рдирд╛ рд╕рдорд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рд╣рдореЗрдВ рдмрд╕ рд╕рдм рдХреБрдЫ рд╕рд╛рдлрд╝ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ:

// Free the RGB image
av_free(buffer);
av_free(pFrameRGB);

// Free the YUV frame
av_free(pFrame);

// Close the codecs
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrig);

// Close the video file
avformat_close_input(&pFormatCtx);

return 0;

рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо рдХрд╛ рдЙрдкрдпреЛрдЧ av_free рд╕реНрдореГрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЖрд╡рдВрдЯрд┐рдд рдХреЗ рд▓рд┐рдП avcode_alloc_frame рдФрд░ av_malloc ред

рдпрд╣ рд╕рдм рдХреЛрдб рд╣реИ! рдЕрдм, рдпрджрд┐ рдЖрдк рд▓рд┐рдирдХреНрд╕ рдпрд╛ рдПрдХ рд╕рдорд╛рди рдордВрдЪ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЪрд▓рд╛рдПрдВ:

gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lm

рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ FFmpeg рдХрд╛ рдкреБрд░рд╛рдирд╛ рд╕рдВрд╕реНрдХрд░рдг рд╣реИ, рддреЛ рдЖрдкрдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд░реВрд░реА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ :

gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lz -lm

рдЕрдзрд┐рдХрд╛рдВрд╢ рдЧреНрд░рд╛рдлрд┐рдХреНрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдХреЛ рдкреАрдкреАрдПрдо рдкреНрд░рд╛рд░реВрдк рдЦреЛрд▓рдирд╛ рд╣реЛрдЧрд╛ред рдХреБрдЫ рдореВрд╡реА рдлрд╛рдЗрд▓реЛрдВ рдкрд░ рдЗрд╕рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ рдЬрд┐рдирдХреЗ рд╕реНрдХреНрд░реИрдиреНрдХреИрдк рд╣рдорд╛рд░реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдП рдЧрдП рдереЗред






рдкрд╛рда 2: рд╕реНрдХреНрд░реАрди рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ тЖР ing тЖТ


рдкреВрд░реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ: tutorial02.c
// tutorial02.c
// A pedagogical video player that will stream through every video frame as fast as it can.
//
// Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, 
// and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
// With updates from https://github.com/chelyaev/ffmpeg-tutorial
// Updates tested on:
// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101, SDL 1.2.15
// on GCC 4.7.2 in Debian February 2015
//
// Use
// 
// gcc -o tutorial02 tutorial02.c -lavformat -lavcodec -lswscale -lz -lm `sdl-config --cflags --libs`
// to build (assuming libavformat and libavcodec are correctly installed, 
// and assuming you have sdl-config. Please refer to SDL docs for your installation.)
//
// Run using
// tutorial02 myvideofile.mpg
//
// to play the video stream on your screen.

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <SDL.h>
#include <SDL_thread.h>

#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif

#include <stdio.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

int main(int argc, char *argv[]) {
  AVFormatContext *pFormatCtx = NULL;
  int             i, videoStream;
  AVCodecContext  *pCodecCtxOrig = NULL;
  AVCodecContext  *pCodecCtx = NULL;
  AVCodec         *pCodec = NULL;
  AVFrame         *pFrame = NULL;
  AVPacket        packet;
  int             frameFinished;
  float           aspect_ratio;
  struct SwsContext *sws_ctx = NULL;

  SDL_Overlay     *bmp;
  SDL_Surface     *screen;
  SDL_Rect        rect;
  SDL_Event       event;

  if(argc < 2) {
    fprintf(stderr, "Usage: test <file>\n");
    exit(1);
  }
  // Register all formats and codecs
  av_register_all();
  
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    exit(1);
  }

  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
  
  // Get a pointer to the codec context for the video stream
  pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }

  // Copy context
  pCodecCtx = avcodec_alloc_context3(pCodec);
  if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }

  // Open codec
  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=av_frame_alloc();

  // Make a screen to put our video
#ifndef __DARWIN__
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
#else
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);
#endif
  if(!screen) {
    fprintf(stderr, "SDL: could not set video mode - exiting\n");
    exit(1);
  }
  
  // Allocate a place to put our YUV image on that screen
  bmp = SDL_CreateYUVOverlay(pCodecCtx->width,
				 pCodecCtx->height,
				 SDL_YV12_OVERLAY,
				 screen);

  // initialize SWS context for software scaling
  sws_ctx = sws_getContext(pCodecCtx->width,
			   pCodecCtx->height,
			   pCodecCtx->pix_fmt,
			   pCodecCtx->width,
			   pCodecCtx->height,
			   PIX_FMT_YUV420P,
			   SWS_BILINEAR,
			   NULL,
			   NULL,
			   NULL
			   );



  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) {
      // Decode video frame
      avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
      
      // Did we get a video frame?
      if(frameFinished) {
	SDL_LockYUVOverlay(bmp);

	AVPicture pict;
	pict.data[0] = bmp->pixels[0];
	pict.data[1] = bmp->pixels[2];
	pict.data[2] = bmp->pixels[1];

	pict.linesize[0] = bmp->pitches[0];
	pict.linesize[1] = bmp->pitches[2];
	pict.linesize[2] = bmp->pitches[1];

	// Convert the image into YUV format that SDL uses
	sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
		  pFrame->linesize, 0, pCodecCtx->height,
		  pict.data, pict.linesize);

	SDL_UnlockYUVOverlay(bmp);
	
	rect.x = 0;
	rect.y = 0;
	rect.w = pCodecCtx->width;
	rect.h = pCodecCtx->height;
	SDL_DisplayYUVOverlay(bmp, &rect);
      
      }
    }
    
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
    SDL_PollEvent(&event);
    switch(event.type) {
    case SDL_QUIT:
      SDL_Quit();
      exit(0);
      break;
    default:
      break;
    }

  }
  
  // Free the YUV frame
  av_frame_free(&pFrame);
  
  // Close the codec
  avcodec_close(pCodecCtx);
  avcodec_close(pCodecCtxOrig);
  
  // Close the video file
  avformat_close_input(&pFormatCtx);
  
  return 0;
}

рдПрд╕рдбреАрдПрд▓ рдФрд░ рд╡реАрдбрд┐рдпреЛ


рд╕реНрдХреНрд░реАрди рдкрд░ рдбреНрд░рд╛рдЗрдВрдЧ рдХреЗ рд▓рд┐рдП рд╣рдо рдПрд╕рдбреАрдПрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред SDL рдХрд╛ рдорддрд▓рдм рд╕рд┐рдВрдкрд▓ рдбрд╛рдпрд░реЗрдХреНрдЯ рд▓реЗрдпрд░ рд╣реИ ред рдпрд╣ рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдорд▓реНрдЯреАрдореАрдбрд┐рдпрд╛ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрдИ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЖрдк рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдЕрдкрдиреЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд▓рд┐рдП рдбреЗрд╡рд▓рдкрд░ рдкреИрдХреЗрдЬ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрджрд┐ рдХреЛрдИ рд╣реЛред рдЗрд╕ рдкрд╛рда рд╕реЗ рдХреЛрдб рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА (рдЕрдиреНрдп рд╕рднреА рдкрд╛рда, рд╡реИрд╕реЗ, рдпрд╣ рднреА рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ)ред

рдПрд╕рдбреАрдПрд▓ рдореЗрдВ рд╕реНрдХреНрд░реАрди рдкрд░ рдбреНрд░рд╛рдЗрдВрдЧ рдХреЗ рд▓рд┐рдП рдХрдИ рддрд░реАрдХреЗ рд╣реИрдВред рдлрд┐рд▓реНрдореЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рд╣реИ рдЬрд┐рд╕реЗ YUV рдУрд╡рд░рд▓реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ред

рдФрдкрдЪрд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ, YUV рднреА рдирд╣реАрдВ, рд▓реЗрдХрд┐рди YCbCrред рд╡реИрд╕реЗ рдХреБрдЫ рд▓реЛрдЧ рддрдм рдмрд╣реБрдд рдЬрд▓ рдЬрд╛рддреЗ рд╣реИрдВ рдЬрдм тАЬYCbCrтАЭ рдХреЛ тАЬYUVтАЭ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛, YUV рдПрдХ рдПрдирд╛рд▓реЙрдЧ рдкреНрд░рд╛рд░реВрдк рд╣реИ, рдФрд░ YCbCr рдПрдХ рдбрд┐рдЬрд┐рдЯрд▓ рдкреНрд░рд╛рд░реВрдк рд╣реИред FFmpeg рдФрд░ SDL рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ рдФрд░ рдореИрдХреНрд░реЛрдЬрд╝ рдореЗрдВ YCbCr рдХреЛ YUV рдХреЗ рд░реВрдк рдореЗрдВ рдирд╛рдорд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рд╣реИред

YUV рдЖрд░рдЬреАрдмреА рдЬреИрд╕реЗ рдХрдЪреНрдЪреЗ рдЫрд╡рд┐ рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреА рдПрдХ рд╡рд┐рдзрд┐ рд╣реИред рдореЛрдЯреЗ рддреМрд░ рдкрд░, рд╡рд╛рдИ рдЪрдордХ рдХрд╛ рдПрдХ рдШрдЯрдХ рд╣реИ , рдФрд░ рдпреВ рдФрд░ рд╡реА рд░рдВрдЧ рдХреЗ рдШрдЯрдХ рд╣реИрдВ ред (рдЖрд░рдЬреАрдмреА рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдпрд╣ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд░рдВрдЧ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдЖрдкрдХреЗ рдкрд╛рд╕ рд╡рд╛рдИ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ 2 рдорд╛рдкреЛрдВ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдпреВ рдФрд░ рд╡реА рдХрд╛ 1 рдорд╛рдк рд╣реЛ рд╕рдХрддрд╛ рд╣реИ )ред YUV рдУрд╡рд░рд▓реЗSDL рдПрдХ рдХрдЪреНрдЪреЗ YUV рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╣ 4 рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ YUV рдлреЙрд░реНрдореЗрдЯ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди YV12 рдЙрдирдореЗрдВ рд╕реЗ рд╕рдмрд╕реЗ рддреЗрдЬ рд╣реИред YUV420P рдирд╛рдордХ рдПрдХ рдФрд░ YUV рдкреНрд░рд╛рд░реВрдк рд╣реИ рдЬреЛ YV12 рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ U рдФрд░ V рдХреЗ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рдЕрджрд▓рд╛-рдмрджрд▓реА рдХреА рдЬрд╛рддреА рд╣реИред 420 рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдпрд╣ 4: 2: 0 рдХреЗ рдЕрдиреБрдкрд╛рдд рдкрд░ рдорд╛рдкрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд, рдЪрдордХ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ 4 рдорд╛рдк рдХреЗ рд▓рд┐рдП 1 рд░рдВрдЧ рдорд╛рдк рд╣реИ, рдЗрд╕рд▓рд┐рдП рд░рдВрдЧ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдХреНрд╡рд╛рд░реНрдЯрд░ рдореЗрдВ рд╡рд┐рддрд░рд┐рдд рдХреА рдЬрд╛рддреА рд╣реИред рдпрд╣ рдмреИрдВрдбрд╡рд┐рдбреНрде рдХреЛ рдмрдЪрд╛рдиреЗ рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдорд╛рдирд╡ рдЖрдВрдЦ рдЕрднреА рднреА рдЗрди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдирд╣реАрдВ рджреЗрдЦрддреА рд╣реИред рдирд╛рдо рдореЗрдВ рд▓реИрдЯрд┐рди рдЕрдХреНрд╖рд░ "рдкреА" рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рд╛рд░реВрдк "рдкреНрд▓рд╛рдирд░" рд╣реИ, рдЬрд┐рд╕рдХрд╛ рд╕реАрдзрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдШрдЯрдХ рд╡рд╛рдИ рд╣реИрдВ ,рдпреВ рдФрд░ рд╡реА рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕рд░рдгрд┐рдпреЛрдВ рдореЗрдВ рд╣реИрдВред FFmpeg рдЫрд╡рд┐рдпреЛрдВ рдХреЛ YUV420P рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ , рдЬреЛ рдмрд╣реБрдд рдорджрджрдЧрд╛рд░ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдХрдИ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдЗрд╕ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИрдВ рдпрд╛ рдЖрд╕рд╛рдиреА рд╕реЗ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реЛ рдЬрд╛рддреА рд╣реИрдВред

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдорд╛рд░реА рд╡рд░реНрддрдорд╛рди рдпреЛрдЬрдирд╛ рдкрд┐рдЫрд▓реЗ рдкрд╛рда рд╕реЗ SaveFrame () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдмрджрд▓рдиреЗ рдФрд░ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рд╣рдорд╛рд░реЗ рдлрд╝реНрд░реЗрдо рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рд╣реИред рд▓реЗрдХрд┐рди рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдПрд╕рдбреАрдПрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреА рдмреБрдирд┐рдпрд╛рджреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдирд╛ рд╣реЛрдЧрд╛ред рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ рдФрд░ рдПрд╕рдбреАрдПрд▓ рдХреЛ рдкреНрд░рд╛рд░рдВрдн рдХрд░реЗрдВ:

#include <SDL.h>
#include <SDL_thread.h>

if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
  fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
  exit(1);
}

SDL_Init () рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХрд┐рди рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред SDL_GetError (), рдмреЗрд╢рдХ, рдпрд╣ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдХрд╛рд░реНрдп рд╣реИред

рдирд┐рд░реНрдорд╛рдг рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ


рдЕрдм рд╣рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░реАрди рдкрд░ рдЬрдЧрд╣ рдЪрд╛рд╣рд┐рдПред рдПрд╕рдбреАрдПрд▓ рдХреЗ рд╕рд╛рде рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рдХреНрд╖реЗрддреНрд░ рдХреЛ рд╕рддрд╣ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ :

SDL_Surface *screen;

screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
if(!screen) {
  fprintf(stderr, "SDL: could not set video mode - exiting\n");
  exit(1);
}

рддреЛ рд╣рдо рдПрдХ рд╕реНрдХреНрд░реАрди рдХреЛ рдПрдХ рджреА рдЧрдИ рдЪреМрдбрд╝рд╛рдИ рдФрд░ рдКрдВрдЪрд╛рдИ рдХреЗ рд╕рд╛рде рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЕрдЧрд▓рд╛ рд╡рд┐рдХрд▓реНрдк рд╕реНрдХреНрд░реАрди рдХреА рдереЛрдбрд╝реА рдЧрд╣рд░рд╛рдИ рд╣реИ - 0 - рдпрд╣ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдореВрд▓реНрдп рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ "рд╡рд░реНрддрдорд╛рди рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд╕рдорд╛рдиред"

рдЕрдм рд╣рдо рдЗрд╕ рд╕реНрдХреНрд░реАрди рдкрд░ рдПрдХ YUV рдУрд╡рд░рд▓реЗ рдмрдирд╛рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд╣рдо рдЗрд╕реЗ рд╡реАрдбрд┐рдпреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░ рд╕рдХреЗрдВ, рдФрд░ рдЗрдореЗрдЬ рдбреЗрдЯрд╛ рдХреЛ YUV420 рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ SWSContext рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░ рд╕рдХреЗрдВ :

SDL_Overlay     *bmp = NULL;
struct SWSContext *sws_ctx = NULL;

bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,
                           SDL_YV12_OVERLAY, screen);

// initialize SWS context for software scaling
sws_ctx = sws_getContext(pCodecCtx->width,
                         pCodecCtx->height,
			 pCodecCtx->pix_fmt,
			 pCodecCtx->width,
			 pCodecCtx->height,
			 PIX_FMT_YUV420P,
			 SWS_BILINEAR,
			 NULL,
			 NULL,
			 NULL
			 );

рдЬреИрд╕рд╛ рдХрд┐ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╣рдо рдЫрд╡рд┐ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдФрд░ FFmpeg рд╕реЗ YUV420 рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП YV12 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ ред

рдЫрд╡рд┐ рдкреНрд░рджрд░реНрд╢рди


рдЦреИрд░, рдпрд╣ рдХрд╛рдлреА рдЖрд╕рд╛рди рдерд╛! рдЕрдм рд╣рдореЗрдВ рд╕рд┐рд░реНрдл рдЫрд╡рд┐ рджрд┐рдЦрд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред рдЪрд▓рд┐рдП рд╣рдо рдЙрд╕ рдЬрдЧрд╣ рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВ рдЬрд╣рд╛рдБ рд╣рдордиреЗ рд╢реВрдЯрд┐рдВрдЧ рдкреВрд░реА рдХреА рдереАред рд╣рдо рдЙрди рд╕рднреА рдЪреАрдЬреЛрдВ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЖрд░рдЬреАрдмреА рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП рдереАрдВ рдФрд░ рд╣рдо рдЕрдкрдиреЗ рдбрд┐рд╕реНрдкреНрд▓реЗ рдХреЛрдб рдХреЗ рд╕рд╛рде рд╕реЗрд╡рдлреНрд░реЗрдо () рдХреЛ рдмрджрд▓рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ ред рдЫрд╡рд┐ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ AVPicture рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рд╣рдорд╛рд░реЗ YUV рдкрд░рд┐рд╢рд┐рд╖реНрдЯ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдкреЙрдЗрдВрдЯрд░реНрд╕ рдФрд░ рд▓рд╛рдЗрди рдЖрдХрд╛рд░ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ :

  if(frameFinished) {
    SDL_LockYUVOverlay(bmp);

    AVPicture pict;
    pict.data[0] = bmp->pixels[0];
    pict.data[1] = bmp->pixels[2];
    pict.data[2] = bmp->pixels[1];

    pict.linesize[0] = bmp->pitches[0];
    pict.linesize[1] = bmp->pitches[2];
    pict.linesize[2] = bmp->pitches[1];

    // Convert the image into YUV format that SDL uses
    sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
	      pFrame->linesize, 0, pCodecCtx->height,
	      pict.data, pict.linesize);
    
    SDL_UnlockYUVOverlay(bmp);

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдУрд╡рд░рд▓реЗ рдХреЛ рдмреНрд▓реЙрдХ рдХрд░рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЗрд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рддреЗ рд╣реИрдВред рдпрд╣ рдПрдХ рдЕрдЪреНрдЫреА рдЖрджрдд рд╣реИ рддрд╛рдХрд┐ рдмрд╛рдж рдореЗрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рди рд╣реЛред AVPicture рд╕рдВрд░рдЪрдирд╛ , рдЬреИрд╕рд╛ рдХрд┐ рдКрдкрд░ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдореЗрдВ рдПрдХ рдбреЗрдЯрд╛ рдкреЙрдЗрдВрдЯрд░ рд╣реИ, рдЬреЛ 4 рдкреЙрдЗрдВрдЯрд░реНрд╕ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИред рдЪреВрдВрдХрд┐ рдпрд╣рд╛рдВ рд╣рдо YUV420P рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ , рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреЗрд╡рд▓ 3 рдЪреИрдирд▓ рд╣реИрдВ рдФрд░ рдЗрд╕рд▓рд┐рдП рдХреЗрд╡рд▓ 3 рдбреЗрдЯрд╛ рд╕реЗрдЯ рд╣реИрдВред рдЕрдиреНрдп рдкреНрд░рд╛рд░реВрдкреЛрдВ рдореЗрдВ рдЕрд▓реНрдлрд╛ рдЪреИрдирд▓ рдпрд╛ рдХреБрдЫ рдФрд░ рдХреЗ рд▓рд┐рдП рдЪреМрдерд╛ рд╕реВрдЪрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рд▓рд╛рдЗрди рдХрд╛ рдЖрдХрд╛рд░ рд╡рд╣ рдЬреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдпреВрдпреВрд╡реА рдУрд╡рд░рд▓реЗ рдореЗрдВ рд╕рдорд╛рди рд╕рдВрд░рдЪрдирд╛рдПрдВ рдкрд┐рдХреНрд╕реЗрд▓ рдФрд░ рдКрдВрдЪрд╛рдЗрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЪрд░ рд╣реИрдВред (рдкрд┐рдЪ, рдкрд┐рдЪ - рдпрджрд┐ рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рдбреЗрдЯрд╛ рд▓рд╛рдЗрди рдХреА рдЪреМрдбрд╝рд╛рдИ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд╕рдбреАрдПрд▓ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡реНрдпрдХреНрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред) рддреЛ, рд╣рдо рдЕрдкрдиреЗ рдУрд╡рд░рд▓реЗ рдкрд░ рддреАрди рдкрд┐рдХреНрдЪрд░рдЯреЗрдЯ рд╕рд░рдгрд┐рдпреЛрдВ рдХрд╛ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ , рдЗрд╕рд▓рд┐рдП рдЬрдм рд╣рдо рд▓рд┐рдЦрддреЗ рд╣реИрдВрдЪрд┐рддреНрд░ , рд╣рдо рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдкрдиреЗ рдУрд╡рд░рд▓реЗ рдореЗрдВ рд░рд┐рдХреЙрд░реНрдб рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЬреЛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕реНрдерд╛рди рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЙрд╕реА рддрд░рд╣, рд╣рдо рдЕрдкрдиреЗ рдЖрдЪреНрдЫрд╛рджрди рд╕реЗ рд╕реАрдзреЗ рд▓рд╛рдЗрди рдЖрдХрд╛рд░ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд░реВрдкрд╛рдВрддрд░рдг рд╕реНрд╡рд░реВрдк рдмрджрд▓рдиреЗ PIX_FMT_YUV420P рдФрд░ рдЙрдкрдпреЛрдЧ sws_scale рд╕реЗ рдкрд╣рд▓реЗ рдХреЗ рд░реВрдк рдореЗрдВред

рдЫрд╡рд┐ рдбреНрд░рд╛рдЗрдВрдЧ


рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдЕрднреА рднреА рдПрд╕рдбреАрдПрд▓ рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рддрд╛рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЙрд╕ рдбреЗрдЯрд╛ рдХреЛ рджрд┐рдЦрд╛ рд╕рдХреЗ рдЬреЛ рд╣рдордиреЗ рдЗрд╕реЗ рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдерд╛ред рд╣рдо рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрдпрдд рднреА рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдлрд┐рд▓реНрдо рдХреЛ рдХрд╣рд╛рдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдХрд┐рд╕ рдЪреМрдбрд╝рд╛рдИ рдФрд░ рдКрдВрдЪрд╛рдИ рддрдХ рдмрдврд╝рд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдорд╛рд░реЗ рд▓рд┐рдП SDL рддрд░рд╛рдЬреВ, рдФрд░ рдпрд╣ рдЖрдкрдХреЗ GPU рдХреЛ рддреЗрдЬрд╝реА рд╕реЗ рд╕реНрдХреЗрд▓ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИ:

SDL_Rect rect;

  if(frameFinished) {
    /* ... code ... */
    // Convert the image into YUV format that SDL uses
    sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
              pFrame->linesize, 0, pCodecCtx->height,
	      pict.data, pict.linesize);
    
    SDL_UnlockYUVOverlay(bmp);
	rect.x = 0;
	rect.y = 0;
	rect.w = pCodecCtx->width;
	rect.h = pCodecCtx->height;
	SDL_DisplayYUVOverlay(bmp, &rect);
  }

рдЕрдм рд╣рдорд╛рд░рд╛ рд╡реАрдбрд┐рдпреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ!

рдЖрдЗрдП рдПрд╕рдбреАрдПрд▓ рдХреА рдПрдХ рдФрд░ рд╡рд┐рд╢реЗрд╖рддрд╛ рджрд┐рдЦрд╛рдПрдВ: рдШрдЯрдирд╛рдУрдВ рдХреА рдкреНрд░рдгрд╛рд▓реА ред рдПрд╕рдбреАрдПрд▓ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдЬрдм рдЖрдк рдПрд╕рдбреАрдПрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдорд╛рдЙрд╕ рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ рдпрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдпрд╛ рдЗрд╕реЗ рдПрдХ рд╕рдВрдХреЗрдд рднреЗрдЬрддреЗ рд╣реИрдВ, рддреЛ рдПрдХ рдШрдЯрдирд╛ рдЙрддреНрдкрдиреНрди рд╣реЛрддреА рд╣реИред рдЖрдкрдХрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рддрдм рдЗрди рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдЗрд░рд╛рджрд╛ рд╣реИред рдЖрдкрдХрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо SDL рдИрд╡реЗрдВрдЯ рдХреЛ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдИрд╡реЗрдВрдЯ рднреА рдмрдирд╛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдПрд╕рдбреАрдПрд▓ рдХреЗ рд╕рд╛рде рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧреА рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдкрд╛рда рд╕рдВрдЦреНрдпрд╛ 4 рдореЗрдВ рджреЗрдЦреЗрдВрдЧреЗред рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ, рд╣рдо рдкреИрдХреЗрдЬ рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж рдХреА рдШрдЯрдирд╛рдУрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рдлрд┐рд▓рд╣рд╛рд▓, рд╣рдо SDL_QUIT рдИрд╡реЗрдВрдЯ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рддрд╛рдХрд┐ рд╣рдо рдмрд╛рд╣рд░ рдирд┐рдХрд▓ рд╕рдХреЗрдВ:

SDL_Event       event;

    av_free_packet(&packet);
    SDL_PollEvent(&event);
    switch(event.type) {
    case SDL_QUIT:
      SDL_Quit();
      exit(0);
      break;
    default:
      break;
    }

рдФрд░ рдЗрд╕рд▓рд┐рдП рд╣рдо рдЬреАрддреЗ рд╣реИрдВ! рд╣рдо рд╕рднреА рдкреБрд░рд╛рдиреЗ рдХрдЪрд░реЗ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рд╣рдо рд╕рдВрдХрд▓рди рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рдпрджрд┐ рдЖрдк рд▓рд┐рдирдХреНрд╕ рдпрд╛ рд▓рд┐рдирдХреНрд╕ рдЬреИрд╕реА рдХрд┐рд╕реА рдЪреАрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдПрд╕рдбреАрдПрд▓ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИ:

gcc -o tutorial02 tutorial02.c -lavformat -lavcodec -lswscale -lz -lm \
`sdl-config --cflags --libs`

рдПрд╕рдбреАрдПрд▓-рд╡рд┐рдиреНрдпрд╛рд╕ рдмрд╕ рдПрд╕рдбреАрдПрд▓ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдХреНрд╖рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреАрд╕реАрд╕реА рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдЭрдВрдбреЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ ред рдЕрдкрдиреЗ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рдЗрд╕ рд╕рдВрдХрд▓рди рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдХреБрдЫ рдФрд░ рдХрд░рдирд╛ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИ; рдХрд┐рд╕реА рднреА рдлрд╛рдпрд░ рдлрд╛рдЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдХреГрдкрдпрд╛ рдЕрдкрдиреЗ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд▓рд┐рдП SDL рдкреНрд░рд▓реЗрдЦрди рджреЗрдЦреЗрдВред рдПрдХ рдмрд╛рд░ рд╕рдВрдХрд▓рд┐рдд, рдЬрд╛рд░реА рд░рдЦреЗрдВ рдФрд░ рдЪрд▓рд╛рдПрдВред

рдЬрдм рдЖрдк рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдЪрд▓рд╛рддреЗ рд╣реИрдВ рддреЛ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ? рд╡реАрдбрд┐рдпреЛ рджреЗрдЦ рд▓рдЧрддрд╛ рд╣реИ рдкрд╛рдЧрд▓ рд╣реЛ рд░рд╣рд╛ рд╣реИ! рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдо рдмрд╕ рд╕рднреА рд╡реАрдбрд┐рдпреЛ рдлреНрд░реЗрдо рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЙрдиреНрд╣реЗрдВ рдлрд┐рд▓реНрдо рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдирд┐рдХрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВред рд╡реАрдбрд┐рдпреЛ рджрд┐рдЦрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдиреЗ рдкрд░ рд╣рдореЗрдВ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрднреА рдХреЛрдб рдирд╣реАрдВ рд╣реИред рдЕрдВрдд рдореЗрдВ (рдкрд╛рда рд╕рдВрдЦреНрдпрд╛ 5 рдореЗрдВ) рд╣рдо рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВрдЧреЗред рд▓реЗрдХрд┐рди рдлрд┐рд▓рд╣рд╛рд▓ рд╣рдо рдХреБрдЫ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╕рдорд╛рди рдпрд╛рдж рдХрд░ рд░рд╣реЗ рд╣реИрдВ: рдзреНрд╡рдирд┐!






рдкрд╛рда 3: рдкреНрд▓реЗ рдзреНрд╡рдирд┐ тЖР тЗС тЖТ


рдкреВрд░реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ: tutorial03.c
// tutorial03.c
// A pedagogical video player that will stream through every video frame as fast as it can
// and play audio (out of sync).
//
// Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, 
// and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
// With updates from https://github.com/chelyaev/ffmpeg-tutorial
// Updates tested on:
// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101, SDL 1.2.15
// on GCC 4.7.2 in Debian February 2015
//
// Use
//
// gcc -o tutorial03 tutorial03.c -lavformat -lavcodec -lswscale -lz -lm `sdl-config --cflags --libs`
// to build (assuming libavformat and libavcodec are correctly installed, 
// and assuming you have sdl-config. Please refer to SDL docs for your installation.)
//
// Run using
// tutorial03 myvideofile.mpg
//
// to play the stream on your screen.

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <SDL.h>
#include <SDL_thread.h>

#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif

#include <stdio.h>
#include <assert.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

#define SDL_AUDIO_BUFFER_SIZE 1024
#define MAX_AUDIO_FRAME_SIZE 192000

typedef struct PacketQueue {
  AVPacketList *first_pkt, *last_pkt;
  int nb_packets;
  int size;
  SDL_mutex *mutex;
  SDL_cond *cond;
} PacketQueue;

PacketQueue audioq;

int quit = 0;

void packet_queue_init(PacketQueue *q) {
  memset(q, 0, sizeof(PacketQueue));
  q->mutex = SDL_CreateMutex();
  q->cond = SDL_CreateCond();
}
int packet_queue_put(PacketQueue *q, AVPacket *pkt) {

  AVPacketList *pkt1;
  if(av_dup_packet(pkt) < 0) {
    return -1;
  }
  pkt1 = av_malloc(sizeof(AVPacketList));
  if (!pkt1)
    return -1;
  pkt1->pkt = *pkt;
  pkt1->next = NULL;
  
  
  SDL_LockMutex(q->mutex);
  
  if (!q->last_pkt)
    q->first_pkt = pkt1;
  else
    q->last_pkt->next = pkt1;
  q->last_pkt = pkt1;
  q->nb_packets++;
  q->size += pkt1->pkt.size;
  SDL_CondSignal(q->cond);
  
  SDL_UnlockMutex(q->mutex);
  return 0;
}
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{
  AVPacketList *pkt1;
  int ret;
  
  SDL_LockMutex(q->mutex);
  
  for(;;) {
    
    if(quit) {
      ret = -1;
      break;
    }

    pkt1 = q->first_pkt;
    if (pkt1) {
      q->first_pkt = pkt1->next;
      if (!q->first_pkt)
	q->last_pkt = NULL;
      q->nb_packets--;
      q->size -= pkt1->pkt.size;
      *pkt = pkt1->pkt;
      av_free(pkt1);
      ret = 1;
      break;
    } else if (!block) {
      ret = 0;
      break;
    } else {
      SDL_CondWait(q->cond, q->mutex);
    }
  }
  SDL_UnlockMutex(q->mutex);
  return ret;
}

int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf, int buf_size) {

  static AVPacket pkt;
  static uint8_t *audio_pkt_data = NULL;
  static int audio_pkt_size = 0;
  static AVFrame frame;

  int len1, data_size = 0;

  for(;;) {
    while(audio_pkt_size > 0) {
      int got_frame = 0;
      len1 = avcodec_decode_audio4(aCodecCtx, &frame, &got_frame, &pkt);
      if(len1 < 0) {
	/* if error, skip frame */
	audio_pkt_size = 0;
	break;
      }
      audio_pkt_data += len1;
      audio_pkt_size -= len1;
      data_size = 0;
      if(got_frame) {
	data_size = av_samples_get_buffer_size(NULL, 
					       aCodecCtx->channels,
					       frame.nb_samples,
					       aCodecCtx->sample_fmt,
					       1);
	assert(data_size <= buf_size);
	memcpy(audio_buf, frame.data[0], data_size);
      }
      if(data_size <= 0) {
	/* No data yet, get more frames */
	continue;
      }
      /* We have data, return it and come back for more later */
      return data_size;
    }
    if(pkt.data)
      av_free_packet(&pkt);

    if(quit) {
      return -1;
    }

    if(packet_queue_get(&audioq, &pkt, 1) < 0) {
      return -1;
    }
    audio_pkt_data = pkt.data;
    audio_pkt_size = pkt.size;
  }
}

void audio_callback(void *userdata, Uint8 *stream, int len) {

  AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
  int len1, audio_size;

  static uint8_t audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2];
  static unsigned int audio_buf_size = 0;
  static unsigned int audio_buf_index = 0;

  while(len > 0) {
    if(audio_buf_index >= audio_buf_size) {
      /* We have already sent all our data; get more */
      audio_size = audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf));
      if(audio_size < 0) {
	/* If error, output silence */
	audio_buf_size = 1024; // arbitrary?
	memset(audio_buf, 0, audio_buf_size);
      } else {
	audio_buf_size = audio_size;
      }
      audio_buf_index = 0;
    }
    len1 = audio_buf_size - audio_buf_index;
    if(len1 > len)
      len1 = len;
    memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);
    len -= len1;
    stream += len1;
    audio_buf_index += len1;
  }
}

int main(int argc, char *argv[]) {
  AVFormatContext *pFormatCtx = NULL;
  int             i, videoStream, audioStream;
  AVCodecContext  *pCodecCtxOrig = NULL;
  AVCodecContext  *pCodecCtx = NULL;
  AVCodec         *pCodec = NULL;
  AVFrame         *pFrame = NULL;
  AVPacket        packet;
  int             frameFinished;
  struct SwsContext *sws_ctx = NULL;
  
  AVCodecContext  *aCodecCtxOrig = NULL;
  AVCodecContext  *aCodecCtx = NULL;
  AVCodec         *aCodec = NULL;

  SDL_Overlay     *bmp;
  SDL_Surface     *screen;
  SDL_Rect        rect;
  SDL_Event       event;
  SDL_AudioSpec   wanted_spec, spec;

  if(argc < 2) {
    fprintf(stderr, "Usage: test <file>\n");
    exit(1);
  }
  // Register all formats and codecs
  av_register_all();
  
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    exit(1);
  }

  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
    
  // Find the first video stream
  videoStream=-1;
  audioStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++) {
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO &&
       videoStream < 0) {
      videoStream=i;
    }
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&
       audioStream < 0) {
      audioStream=i;
    }
  }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
  if(audioStream==-1)
    return -1;
   
  aCodecCtxOrig=pFormatCtx->streams[audioStream]->codec;
  aCodec = avcodec_find_decoder(aCodecCtxOrig->codec_id);
  if(!aCodec) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  // Copy context
  aCodecCtx = avcodec_alloc_context3(aCodec);
  if(avcodec_copy_context(aCodecCtx, aCodecCtxOrig) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }

  // Set audio settings from codec info
  wanted_spec.freq = aCodecCtx->sample_rate;
  wanted_spec.format = AUDIO_S16SYS;
  wanted_spec.channels = aCodecCtx->channels;
  wanted_spec.silence = 0;
  wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
  wanted_spec.callback = audio_callback;
  wanted_spec.userdata = aCodecCtx;
  
  if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {
    fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
    return -1;
  }

  avcodec_open2(aCodecCtx, aCodec, NULL);

  // audio_st = pFormatCtx->streams[index]
  packet_queue_init(&audioq);
  SDL_PauseAudio(0);

  // Get a pointer to the codec context for the video stream
  pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
  
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }

  // Copy context
  pCodecCtx = avcodec_alloc_context3(pCodec);
  if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }

  // Open codec
  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=av_frame_alloc();

  // Make a screen to put our video

#ifndef __DARWIN__
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
#else
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);
#endif
  if(!screen) {
    fprintf(stderr, "SDL: could not set video mode - exiting\n");
    exit(1);
  }
  
  // Allocate a place to put our YUV image on that screen
  bmp = SDL_CreateYUVOverlay(pCodecCtx->width,
				 pCodecCtx->height,
				 SDL_YV12_OVERLAY,
				 screen);

  // initialize SWS context for software scaling
  sws_ctx = sws_getContext(pCodecCtx->width,
			   pCodecCtx->height,
			   pCodecCtx->pix_fmt,
			   pCodecCtx->width,
			   pCodecCtx->height,
			   PIX_FMT_YUV420P,
			   SWS_BILINEAR,
			   NULL,
			   NULL,
			   NULL
			   );

  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) {
      // Decode video frame
      avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
      
      // Did we get a video frame?
      if(frameFinished) {
	SDL_LockYUVOverlay(bmp);

	AVPicture pict;
	pict.data[0] = bmp->pixels[0];
	pict.data[1] = bmp->pixels[2];
	pict.data[2] = bmp->pixels[1];

	pict.linesize[0] = bmp->pitches[0];
	pict.linesize[1] = bmp->pitches[2];
	pict.linesize[2] = bmp->pitches[1];

	// Convert the image into YUV format that SDL uses	
	sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
		  pFrame->linesize, 0, pCodecCtx->height,
		  pict.data, pict.linesize);
	
	SDL_UnlockYUVOverlay(bmp);
	
	rect.x = 0;
	rect.y = 0;
	rect.w = pCodecCtx->width;
	rect.h = pCodecCtx->height;
	SDL_DisplayYUVOverlay(bmp, &rect);
	av_free_packet(&packet);
      }
    } else if(packet.stream_index==audioStream) {
      packet_queue_put(&audioq, &packet);
    } else {
      av_free_packet(&packet);
    }
    // Free the packet that was allocated by av_read_frame
    SDL_PollEvent(&event);
    switch(event.type) {
    case SDL_QUIT:
      quit = 1;
      SDL_Quit();
      exit(0);
      break;
    default:
      break;
    }

  }

  // Free the YUV frame
  av_frame_free(&pFrame);
  
  // Close the codecs
  avcodec_close(pCodecCtxOrig);
  avcodec_close(pCodecCtx);
  avcodec_close(aCodecCtxOrig);
  avcodec_close(aCodecCtx);
  
  // Close the video file
  avformat_close_input(&pFormatCtx);
  
  return 0;
}

рдСрдбрд┐рдпреЛ


рдЕрдм рд╣рдо рдЪрд╛рд╣реЗрдВрдЧреЗ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдзреНрд╡рдирд┐ рдмрдЬреЗрдВред рдПрд╕рдбреАрдПрд▓ рд╣рдореЗрдВ рдзреНрд╡рдирд┐ рдмрдЬрд╛рдиреЗ рдХреЗ рддрд░реАрдХреЗ рднреА рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред SDL_OpenAudio () рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдСрдбрд┐рдпреЛ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЛ рд╕реНрд╡рдпрдВ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ SDL_AudioSpec рд╕рдВрд░рдЪрдирд╛ рдХреЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ , рдЬрд┐рд╕рдореЗрдВ рдСрдбрд┐рдпреЛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рд╛рд░реА рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдмрдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд╣реИрдВред

рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рджрд┐рдЦрд╛рдПрдВ, рд╣рдо рдкрд╣рд▓реЗ рдмрддрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдХрдВрдкреНрдпреВрдЯрд░ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рдСрдбрд┐рдпреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИред рдбрд┐рдЬрд┐рдЯрд▓ рдСрдбрд┐рдпреЛ рдореЗрдВ рдирдореВрдиреЛрдВ рдХреА рдПрдХ рд▓рдВрдмреА рдзрд╛рд░рд╛ рд╣реЛрддреА рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдзреНрд╡рдирд┐ рддрд░рдВрдЧ рдХреЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЕрд░реНрде рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддрд╛ рд╣реИред рдзреНрд╡рдирд┐рдпреЛрдВ рдХреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдирдореВрдирд╛рдХрд░рдг рджрд░ рдкрд░ рджрд░реНрдЬ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдмрд╕ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдирдореВрдирд╛ рдХрд┐рддрдиреА рдЬрд▓реНрджреА рдЦреЗрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рдирдореВрдиреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рдорд╛рдкрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдиреБрдорд╛рдирд┐рдд рдирдореВрдирд╛ рдЖрд╡реГрддреНрддрд┐рдпреЛрдВ 22,050 рдФрд░ 44,100 рдирдореВрдиреЗ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рд╣реИрдВ, рдЬреЛ рдХреНрд░рдорд╢рдГ рд░реЗрдбрд┐рдпреЛ рдФрд░ рд╕реАрдбреА рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдЧрддрд┐ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЕрдзрд┐рдХрд╛рдВрд╢ рдСрдбрд┐рдпреЛ рдореЗрдВ рд╕реНрдЯреАрд░рд┐рдпреЛ рдпрд╛ рд╕рд░рд╛рдЙрдВрдб рд╕рд╛рдЙрдВрдб рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдЪреИрдирд▓ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдирдореВрдирд╛ рд╕реНрдЯреАрд░рд┐рдпреЛ рдореЗрдВ рд╣реИ, рддреЛ рдирдореВрдиреЗ рдПрдХ рд╕рдордп рдореЗрдВ рджреЛ рдЖрдПрдВрдЧреЗред рдЬрдм рд╣рдо рдлрд┐рд▓реНрдо рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдкрддрд╛ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдХрд┐рддрдиреЗ рдирдореВрдиреЗ рдорд┐рд▓реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди FFmpeg рдЯреВрдЯреЗ рд╣реБрдП рдирдореВрдиреЛрдВ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ - рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рднреА рд╣реИ рдХрд┐ рдпрд╣ рд╕реНрдЯреАрд░рд┐рдпреЛ рдирдореВрдиреЗ рдХреЛ рдЕрд▓рдЧ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред

рдПрд╕рдбреАрдПрд▓ рдореЗрдВ рдСрдбрд┐рдпреЛ рдЦреЗрд▓рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИред рдзреНрд╡рдирд┐ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдП рдЧрдП рд╣реИрдВ: рдирдореВрдирд╛ рдЖрд╡реГрддреНрддрд┐, рдЪреИрдирд▓реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛, рдЖрджрд┐ред рдФрд░ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рднреА рд╕реЗрдЯ рдХрд░реЗрдВред рдЬрдм рд╣рдо рдзреНрд╡рдирд┐ рдмрдЬрд╛рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдПрд╕рдбреАрдПрд▓ рд▓рдЧрд╛рддрд╛рд░ рдЗрд╕ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ рдФрд░ рдЗрд╕реЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдСрдбрд┐рдпреЛ рдмрдлрд░ рднрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣реЗрдЧрд╛ред рдЗрд╕ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ SDL_AudioSpec рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдбрд╛рд▓рдиреЗ рдХреЗ рдмрд╛рдж , рд╣рдо SDL_OpenAudio () рдХрд╣рддреЗ рд╣реИрдВ, рдЬреЛ рдСрдбрд┐рдпреЛ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЛ рдЦреЛрд▓реЗрдЧрд╛ рдФрд░ рд╣рдореЗрдВ рдПрдХ рдФрд░ AudioSpec рд╕рдВрд░рдЪрдирд╛ рд▓реМрдЯрд╛рдПрдЧрд╛ ред рдпреЗ рдРрд╕реА рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдБ рд╣реИрдВ рдЬрд┐рдирдХрд╛ рд╣рдо рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ - рдЗрд╕ рдмрд╛рдд рдХреА рдХреЛрдИ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╣рдордиреЗ рдЬреЛ рдорд╛рдВрдЧрд╛ рдерд╛, рд╡рд╣ рдмрд┐рд▓рдХреБрд▓ рд╡реИрд╕рд╛ рд╣реА рдорд┐рд▓реЗрдЧрд╛!

рдСрдбрд┐рдпреЛ рд╕реЗрдЯрд┐рдВрдЧ


рдмрд╕ рдЗрд╕реЗ рдЕрднреА рдХреЗ рд▓рд┐рдП рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рддрдХ рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреЛрдИ рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд╣реИ! рдЖрдЗрдП рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ рдЙрд╕ рд╕реНрдерд╛рди рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ рдЬрд╣рд╛рдВ рд╣рдордиреЗ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдкрд╛рдпрд╛ рдФрд░ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ рдХрд┐ рдХреМрди рд╕реА рд╕реНрдЯреНрд░реАрдо рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд╣реИ:

// Find the first video stream
videoStream=-1;
audioStream=-1;
for(i=0; i < pFormatCtx->nb_streams; i++) {
  if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO
     &&
       videoStream < 0) {
    videoStream=i;
  }
  if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&
     audioStream < 0) {
    audioStream=i;
  }
}
if(videoStream==-1)
  return -1; // Didn't find a video stream
if(audioStream==-1)
  return -1;

рдпрд╣рд╛рдВ рд╣рдо AVCodecContext рд╕реЗ рд╕реНрдЯреНрд░реАрдо рдХреА рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ , рдареАрдХ рдЙрд╕реА рддрд░рд╣ рдЬреИрд╕реЗ рд╣рдордиреЗ рд╡реАрдбрд┐рдпреЛ рдХреЛрдб рдХреЗ рд╕рд╛рде рдХреА рдереА:

AVCodecContext *aCodecCtxOrig;
AVCodecContext *aCodecCtx;

aCodecCtxOrig=pFormatCtx->streams[audioStream]->codec;

рдпрджрд┐ рдЖрдкрдХреЛ рдпрд╛рдж рд╣реИ, рддреЛ рдкрд┐рдЫрд▓реЗ рдкрд╛рдареЛрдВ рдореЗрдВ, рд╣рдореЗрдВ рдЕрднреА рднреА рдСрдбрд┐рдпреЛ рдХреЛрдбреЗрдХ рд╕реНрд╡рдпрдВ рд╣реА рдЦреЛрд▓рдирд╛ рд╣реИред рдпрд╣ рдЖрд╕рд╛рди рд╣реИ:

AVCodec         *aCodec;

aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
if(!aCodec) {
  fprintf(stderr, "Unsupported codec!\n");
  return -1;
}
// Copy context
aCodecCtx = avcodec_alloc_context3(aCodec);
if(avcodec_copy_context(aCodecCtx, aCodecCtxOrig) != 0) {
  fprintf(stderr, "Couldn't copy codec context");
  return -1; // Error copying codec context
}
/* set up SDL Audio here */

avcodec_open2(aCodecCtx, aCodec, NULL);

рдХреЛрдбреЗрдХ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:

wanted_spec.freq = aCodecCtx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = aCodecCtx->channels;
wanted_spec.silence = 0;
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec.callback = audio_callback;
wanted_spec.userdata = aCodecCtx;

if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {
  fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
  return -1;
}

рдЖрдЗрдП рдкреНрд░рддреНрдпреЗрдХ рдЖрдЗрдЯрдо рдкрд░ рдЬрд╛рдПрдВ:
  • freq (рдЖрд╡реГрддреНрддрд┐): рдирдореВрдирд╛рдХрд░рдг рджрд░, рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред
  • format (): SDL , . ┬лS┬╗ ┬лS16SYS┬╗ ┬л┬╗, 16 , 16 , ┬лSYS┬╗ , , . , avcodec_decode_audio2 .
  • channels (): .
  • silence (): , . 0.
  • samples (): , , SDL , . - 512 8192; FFplay, , 1024.
  • рдХреЙрд▓рдмреИрдХ (рдХреЙрд▓рдмреИрдХ): рдпрд╣рд╛рдВ рд╣рдо рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдмрд╛рдж рдореЗрдВ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдмрд╛рдд рдХрд░реЗрдВрдЧреЗред
  • userdata : SDL рд╣рдорд╛рд░реЗ рдХреЙрд▓рдмреИрдХ рдХреЛ рдХрд┐рд╕реА рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдХреЛ рдПрдХ рдЕрд╢рдХреНрдд рд╕реВрдЪрдХ рджреЗрдЧрд╛ рдЬреЛ рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо рдЙрд╕реЗ рдЕрдкрдиреЗ рдХреЛрдбреЗрдХ рд╕рдВрджрд░реНрдн рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ; рдереЛрдбрд╝рд╛ рдХрдо рдХреНрдпреЛрдВ рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред

рдЕрдВрдд рдореЗрдВ, SDL_OpenAudio рдХреЗ рд╕рд╛рде рдСрдбрд┐рдпреЛ рдЦреЛрд▓реЗрдВ ред

рдХрддрд╛рд░


рдФрд░ рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ! рдЕрдм рд╣рдо рд╕реНрдЯреНрд░реАрдо рд╕реЗ рдСрдбрд┐рдпреЛ рдЬрд╛рдирдХрд╛рд░реА рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЗрд╕ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдХреНрдпрд╛ рдХрд░реЗрдВ? рд╣рдо рдореВрд╡реА рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд▓рдЧрд╛рддрд╛рд░ рдкреИрдХреЗрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдЙрд╕реА рд╕рдордп, SDL рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛! рдЗрд╕рдХрд╛ рд╕рдорд╛рдзрд╛рди рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреА рд╡реИрд╢реНрд╡рд┐рдХ рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдСрдбрд┐рдпреЛ рдкреИрдХреЗрдЯ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ_рдХреЙрд▓рдмреИрдХ рдореЗрдВ рдСрдбрд┐рдпреЛ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╣реЛ! рддреЛ, рдпрд╣рд╛рдБ рд╣рдо рдкреИрдХреЗрдЯ рдХрддрд╛рд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдХрд░реЗрдВрдЧреЗред FFmpeg рдХреЗ рдкрд╛рд╕ рдЗрд╕рдХреА рдорджрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдВрд░рдЪрдирд╛ рднреА рд╣реИ: AVPacketList , рдЬреЛ рдХрд┐ рдкреИрдХреЗрдЬреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рдХреА рдЧрдИ рд╕реВрдЪреА рд╣реИред рдпрд╣рд╛рдБ рд╣рдорд╛рд░реА рдХрддрд╛рд░ рд╕рдВрд░рдЪрдирд╛ рд╣реИ:

typedef struct PacketQueue {
  AVPacketList *first_pkt, *last_pkt;
  int nb_packets;
  int size;
  SDL_mutex *mutex;
  SDL_cond *cond;
} PacketQueue;

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ nb_packets рдЖрдХрд╛рд░ рдореЗрдВ рднрд┐рдиреНрди рд╣реИ - рдЖрдХрд╛рд░ рдмрд╛рдЗрдЯ рдХреЗ рдЖрдХрд╛рд░ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╣рдо рдкреИрдХреЗрдЯ-> рдЖрдХрд╛рд░ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдореНрдпреВрдЯреЗрдХреНрд╕ рдФрд░ рдПрдХ рд╕реНрдерд┐рддрд┐ рдЪрд░ рд╣реИред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ SDL рдПрдХ рдЕрд▓рдЧ рд╕реНрдЯреНрд░реАрдо рдХреЗ рд░реВрдк рдореЗрдВ рдСрдбрд┐рдпреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рд╣рдо рдХрддрд╛рд░ рдХреЛ рдареАрдХ рд╕реЗ рдЕрд╡рд░реБрджреНрдз рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛ рдХреЛ рдмрд░реНрдмрд╛рдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдХрддрд╛рд░ рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рд╕реНрд╡рд╛рднрд┐рдорд╛рдиреА рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЛ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдХрддрд╛рд░ рдХреИрд╕реЗ рдмрдирд╛рдИ рдЬрд╛рддреА рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдпрд╣ рднреА рджрд┐рдЦрд╛рдПрдВрдЧреЗ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╣реИ рддрд╛рдХрд┐ рдПрд╕рдбреАрдПрд▓ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕реАрдЦрдирд╛ рдЖрдкрдХреЗ рд▓рд┐рдП рдЖрд╕рд╛рди рд╣реЛред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдХрддрд╛рд░ рдХреЛ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рддреЗ рд╣реИрдВ:

void packet_queue_init(PacketQueue *q) {
  memset(q, 0, sizeof(PacketQueue));
  q->mutex = SDL_CreateMutex();
  q->cond = SDL_CreateCond();
}

рдлрд┐рд░ рд╣рдорд╛рд░реА рдХрддрд╛рд░ рдореЗрдВ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдорд╛рд░реЛрд╣ рдмрдирд╛рдПрдБ:

int packet_queue_put(PacketQueue *q, AVPacket *pkt) {

  AVPacketList *pkt1;
  if(av_dup_packet(pkt) < 0) {
    return -1;
  }
  pkt1 = av_malloc(sizeof(AVPacketList));
  if (!pkt1)
    return -1;
  pkt1->pkt = *pkt;
  pkt1->next = NULL;
  
  
  SDL_LockMutex(q->mutex);
  
  if (!q->last_pkt)
    q->first_pkt = pkt1;
  else
    q->last_pkt->next = pkt1;
  q->last_pkt = pkt1;
  q->nb_packets++;
  q->size += pkt1->pkt.size;
  SDL_CondSignal(q->cond);
  
  SDL_UnlockMutex(q->mutex);
  return 0;
}

SDL_LockMutex () рдХрддрд╛рд░ рдореЗрдВ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рдЕрд╡рд░реБрджреНрдз рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рд╣рдо рдХреБрдЫ рдЬреЛрдбрд╝ рд╕рдХреЗрдВ, рдФрд░ рдлрд┐рд░ SDL_CondSignal () рд╣рдорд╛рд░реЗ рдкреНрд░рд╛рдкреНрдд рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдВрдХреЗрдд рднреЗрдЬрддрд╛ рд╣реИ (рдЕрдЧрд░ рдпрд╣ рдЙрдореНрдореАрдж рдХрд░рддрд╛ рд╣реИ) рд╣рдорд╛рд░реЗ рд╕рд╢рд░реНрдд рдЪрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдпрд╣ рдмрддрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдбреЗрдЯрд╛ рд╣реИ рдФрд░ рдЬрд╛рд░реА рд░рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЖрдЧреЗ рдХреЗ рд▓рд┐рдПред рдореНрдпреВрдЯреЗрдХреНрд╕ рдЕрдирд▓реЙрдХ рдХрд░реЗрдВред

рдпрд╣рд╛рдБ рдЗрд╕реА рд╣реИ get рд╕рдорд╛рд░реЛрд╣ ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдХреИрд╕реЗ SDL_CondWait () рдлрд╝рдВрдХреНрд╢рди рдмреНрд▓реЙрдХ рдмрдирд╛рддрд╛ рд╣реИ (рдпрд╛рдиреА рдЬрдм рддрдХ рд╣рдореЗрдВ рдбреЗрдЯрд╛ рдирд╣реАрдВ рдорд┐рд▓рддрд╛ рд╣реИ) рдпрджрд┐ рд╣рдо рдЗрд╕реЗ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рддреЗ рд╣реИрдВ:

int quit = 0;

static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) {
  AVPacketList *pkt1;
  int ret;
  
  SDL_LockMutex(q->mutex);
  
  for(;;) {
    
    if(quit) {
      ret = -1;
      break;
    }

    pkt1 = q->first_pkt;
    if (pkt1) {
      q->first_pkt = pkt1->next;
      if (!q->first_pkt)
	q->last_pkt = NULL;
      q->nb_packets--;
      q->size -= pkt1->pkt.size;
      *pkt = pkt1->pkt;
      av_free(pkt1);
      ret = 1;
      break;
    } else if (!block) {
      ret = 0;
      break;
    } else {
      SDL_CondWait(q->cond, q->mutex);
    }
  }
  SDL_UnlockMutex(q->mutex);
  return ret;
}

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдордиреЗ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдПрдХ рдЕрдирдиреНрдд рдЪрдХреНрд░ рдореЗрдВ рд▓рдкреЗрдЯ рджрд┐рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХреБрдЫ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ рдпрджрд┐ рд╣рдо рдЗрд╕реЗ рдмреНрд▓реЙрдХ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо SDL_CondWait () рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рдореЗрд╢рд╛ рдХреЗ рд▓рд┐рдП рд▓реВрдкрд┐рдВрдЧ рд╕реЗ рдмрдЪрддреЗ рд╣реИрдВ ред рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ, рд╕рднреА CondWait SDL_CondSignal () (рдпрд╛ SDL_CondBroadcast ()) рд╕реЗ рдПрдХ рд╕рдВрдХреЗрдд рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рдЬрд╛рд░реА рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдРрд╕рд╛ рд▓рдЧ рд░рд╣рд╛ рд╣реИ рдХрд┐ рд╣рдордиреЗ рдЗрд╕реЗ рдореНрдпреВрдЯреЗрдХреНрд╕ рдореЗрдВ рдкрдХрдбрд╝ рд▓рд┐рдпрд╛ рд╣реИ - рдЕрдЧрд░ рд╣рдо рд▓реЙрдХ рдХреЛ рдкрдХрдбрд╝рддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░рд╛ рдкреБрдЯ рдлрд╝рдВрдХреНрд╢рди рдХреБрдЫ рднреА рдХрддрд╛рд░ рдореЗрдВ рдирд╣реАрдВ рд░рдЦ рд╕рдХрддрд╛ рд╣реИ! рд╣рд╛рд▓рд╛рдБрдХрд┐, рд╣рдорд╛рд░реЗ рд▓рд┐рдП SDL_CondWait () рднреА рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рдЕрдирдмреНрд▓реЙрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ рдЬреЛ рд╣рдо рдЗрд╕реЗ рджреЗрддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рд╕рд┐рдЧреНрдирд▓ рдорд┐рд▓рддреЗ рд╣реА рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рд▓реЙрдХ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВред

рд╣рд░ рдлрд╛рдпрд░рдореИрди рдХреЗ рд▓рд┐рдП


рдЖрдк рдпрд╣ рднреА рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╡реИрд╢реНрд╡рд┐рдХ рдЕрд╡рдХрд╛рд╢ рдЪрд░ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдордиреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рд╕рд┐рдЧреНрдирд▓ рд╕реЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ (рдПрд╕рдбреАрдПрд▓ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ TERM рд╕рд┐рдЧреНрдирд▓ рдЖрджрд┐ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИ )ред рдЕрдиреНрдпрдерд╛, рдзрд╛рдЧрд╛ рд╣рдореЗрд╢рд╛ рдХреЗ рд▓рд┐рдП рдЬрд╛рд░реА рд░рд╣реЗрдЧрд╛, рдФрд░ рд╣рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛ рдХрд┐рд▓ -9 рд╕реЗ рдорд╛рд░рдирд╛ рд╣реЛрдЧрд╛ :

  SDL_PollEvent(&event);
  switch(event.type) {
  case SDL_QUIT:
    quit = 1;

рд╣рдо рдирд┐рдХрд╛рд╕ рдзреНрд╡рдЬ рдХреЛ 1 рдкрд░ рд╕реЗрдЯ рдХрд░реЗрдВрдЧреЗред

рд╣рдо рдкреИрдХреЗрдЬ рдЦрд┐рд▓рд╛рддреЗ рд╣реИрдВ


рдпрд╣ рдХреЗрд╡рд▓ рд╣рдорд╛рд░реА рдХрддрд╛рд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИ:

PacketQueue audioq;
main() {
...
  avcodec_open2(aCodecCtx, aCodec, NULL);

  packet_queue_init(&audioq);
  SDL_PauseAudio(0);

SDL_PauseAudio () рдЖрдЦрд┐рд░рдХрд╛рд░ рдСрдбрд┐рдпреЛ рдпреВрдирд┐рдЯ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдпрд╣ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рддреЛ рдпрд╣ рдЪреБрдкреНрдкреА рдХреЛ рдкреБрди: рдкреЗрд╢ рдХрд░рддрд╛ рд╣реИ; рд▓реЗрдХрд┐рди рдпрд╣ рддреБрд░рдВрдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред

рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдХрддрд╛рд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рд╣реИ, рдЕрдм рд╣рдо рдЙрд╕реЗ рдкреИрдХреЗрдЯ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рд╣рдо рдЕрдкрдиреЗ рдкреИрдХреЗрдЬ рдкрдврд╝рдиреЗ рдХреЗ рдЪрдХреНрд░ рдкрд░ рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВ:

while(av_read_frame(pFormatCtx, &packet)>=0) {
  // Is this a packet from the video stream?
  if(packet.stream_index==videoStream) {
    // Decode video frame
    ....
    }
  } else if(packet.stream_index==audioStream) {
    packet_queue_put(&audioq, &packet);
  } else {
    av_free_packet(&packet);
  }

рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдкреИрдХреЗрдЬ рдЬрд╛рд░реА рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдЗрд╕реЗ рдмрд╛рдж рдореЗрдВ рдЬрд╛рд░реА рдХрд░реЗрдВрдЧреЗ рдЬрдм рд╣рдо рдбрд┐рдХреНрд░рд┐рдкреНрдЯ рдХрд░реЗрдВрдЧреЗред

рдкреБрдирдГ рдкреНрд░рд╛рдкреНрдд рдкреИрдХреЗрдЬ


рдЕрдм рдЪрд▓рд┐рдП рдХрддрд╛рд░ рд╕реЗ рдкреИрдХреЗрдЯ рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдВрдд рдореЗрдВ рд╣рдорд╛рд░рд╛ рдСрдбрд┐рдпреЛ_рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХрд░реЗрдВред рдХреЙрд▓рдмреИрдХ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:

void callback(void *userdata, Uint8 *stream, int len)

userdata , рд╡рд╣ рд╕реВрдЪрдХ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ SDL рджрд┐рдпрд╛ рдерд╛, рд╕реНрдЯреНрд░реАрдо рдмрдлрд░ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдСрдбрд┐рдпреЛ рдбреЗрдЯрд╛ рд▓рд┐рдЦреЗрдВрдЧреЗ, рдФрд░ рд▓реЗрди рдЗрд╕ рдмрдлрд░ рдХрд╛ рдЖрдХрд╛рд░ рд╣реИред рдпрд╣рд╛рдБ рдХреЛрдб рд╣реИ:

void audio_callback(void *userdata, Uint8 *stream, int len) {

  AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
  int len1, audio_size;

  static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
  static unsigned int audio_buf_size = 0;
  static unsigned int audio_buf_index = 0;

  while(len > 0) {
    if(audio_buf_index >= audio_buf_size) {
      /* We have already sent all our data; get more */
      audio_size = audio_decode_frame(aCodecCtx, audio_buf,
                                      sizeof(audio_buf));
      if(audio_size < 0) {
	/* If error, output silence */
	audio_buf_size = 1024;
	memset(audio_buf, 0, audio_buf_size);
      } else {
	audio_buf_size = audio_size;
      }
      audio_buf_index = 0;
    }
    len1 = audio_buf_size - audio_buf_index;
    if(len1 > len)
      len1 = len;
    memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);
    len -= len1;
    stream += len1;
    audio_buf_index += len1;
  }
}

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдПрдХ рд╕рд░рд▓ рдкрд╛рд╢ рдПрдХ рдФрд░ рд╕рдорд╛рд░реЛрд╣ рдХреЗ рдЕрд░реНрдХ рдбреЗрдЯрд╛ рд╣реИ рдХрд┐ рд╣рдо рдиреЗ рд▓рд┐рдЦрд╛ рд╣реИ рдХрд┐, рд╣реИ audio_decode_frame (), рдПрдХ рдордзреНрдпрд╡рд░реНрддреА рдмрдлрд░ рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдХреА рдмрдЪрдд рд╣реЛрддреА рд╣реИ рд▓рд┐рдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИ рд▓реЗрди рдзрд╛рд░рд╛ рдмрд╛рдЗрдЯреНрд╕ рдФрд░ рдЕрдзрд┐рдХ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЕрднреА рднреА рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИ рдпрд╛ рдмрд╛рдж рдХреЗ рд▓рд┐рдП, рдЕрдЧрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рдмрдЪрд╛ рд╣реИред рдХреЗ рдЖрдХрд╛рд░ audio_buf 1.5 рдЧреБрдирд╛ рдмрдбрд╝рд╛ рдСрдбрд┐рдпреЛ рдлреНрд░реЗрдо рдХреЗ рдЖрдХрд╛рд░ рдХрд┐ FFmpeg рдЬреЛ рд╣рдореЗрдВ рдПрдХ рдЕрдЪреНрдЫрд╛ рдорд╛рд░реНрдЬрд┐рди рджреЗрддрд╛ рд╣реИ рд╣рдореЗрдВ рджреЗ рджреЗрдВрдЧреЗ, рд╣реИред

рдЕрдВрддрд┐рдо рдСрдбрд┐рдпреЛ рдбрд┐рдХреНрд░рд┐рдкреНрд╢рди


рдЖрдЗрдП рдСрдбрд┐рдпреЛ_рдбрдмреНрд▓реВ_рдлреНрд░реЗрдо рдбрд┐рдХреЛрдбрд░ рдХреЗ рдЗрдирд╕рд╛рдЗрдб рдХреЛ рджреЗрдЦреЗрдВ :

int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf,
                       int buf_size) {

  static AVPacket pkt;
  static uint8_t *audio_pkt_data = NULL;
  static int audio_pkt_size = 0;
  static AVFrame frame;

  int len1, data_size = 0;

  for(;;) {
    while(audio_pkt_size > 0) {
      int got_frame = 0;
      len1 = avcodec_decode_audio4(aCodecCtx, &frame, &got_frame, &pkt);
      if(len1 < 0) {
	/* if error, skip frame */
	audio_pkt_size = 0;
	break;
      }
      audio_pkt_data += len1;
      audio_pkt_size -= len1;
      data_size = 0;
      if(got_frame) {
	data_size = av_samples_get_buffer_size(NULL, 
					       aCodecCtx->channels,
					       frame.nb_samples,
					       aCodecCtx->sample_fmt,
					       1);
	assert(data_size <= buf_size);
	memcpy(audio_buf, frame.data[0], data_size);
      }
      if(data_size <= 0) {
	/* No data yet, get more frames */
	continue;
      }
      /* We have data, return it and come back for more later */
      return data_size;
    }
    if(pkt.data)
      av_free_packet(&pkt);

    if(quit) {
      return -1;
    }

    if(packet_queue_get(&audioq, &pkt, 1) < 0) {
      return -1;
    }
    audio_pkt_data = pkt.data;
    audio_pkt_size = pkt.size;
  }
}

рдкреВрд░реА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрдд рдХреЗ рдкрд╛рд╕ рд╢реБрд░реВ рд╣реЛрддреА рд╣реИ, рдЬрд╣рд╛рдВ рд╣рдо packet_queue_get () рдХрд╣рддреЗ рд╣реИрдВред рд╣рдо рдкреИрдХреЗрдЯ рдХреЛ рдХрддрд╛рд░ рд╕реЗ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рдЙрд╕рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдмрдЪрд╛рддреЗ рд╣реИрдВред рдлрд┐рд░, рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрдХреЗрдЬ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо avcodec_decode_audio4 () рдХрд╣рддреЗ рд╣реИрдВ, рдЬреЛ рдЙрд╕рдХреА рдмрд╣рди рдХреЗ рдХрд╛рд░реНрдп avcodec_decode_video () рдХреЗ рд╕рдорд╛рди рд╣реИ , рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдкреИрдХреЗрдЬ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдлреНрд░реЗрдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдкреИрдХреЗрдЯ рд╕реЗ рд╕рднреА рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЗрд╕реЗ рдХрдИ рдмрд╛рд░ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред рдлреНрд░реЗрдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдмрд╕ рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ рдмрдлрд░ рдкрд░ рдХреЙрдкреА рдХрд░рддреЗ рд╣реИрдВ, рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реБрдП рдХрд┐ рдбреЗрдЯрд╛_рд╕рд╛рдЗрдЬрд╝ рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ рдмрдлрд░ рд╕реЗ рдЫреЛрдЯрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, Audio_buf рдХрд╛рд╕реНрдЯрд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╛рдж рд░рдЦреЗрдВрд╕рд╣реА рдкреНрд░рдХрд╛рд░ рд╕реЗ, рдХреНрдпреЛрдВрдХрд┐ SDL рдПрдХ 8-рдмрд┐рдЯ int рдмрдлрд░ рджреЗрддрд╛ рд╣реИ, рдФрд░ FFmpeg рд╣рдореЗрдВ 16-рдмрд┐рдЯ int рдмрдлрд░ рдореЗрдВ рдбреЗрдЯрд╛ рджреЗрддрд╛ рд╣реИред рдЖрдкрдХреЛ len1 рдФрд░ data_size рдХреЗ рдмреАрдЪ рдХреЗ рдЕрдВрддрд░ рдкрд░ рднреА рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП ред len1 рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдкреИрдХреЗрдЬ рдХрд╛ рдЖрдХрд╛рд░ рд╣реИ, рдФрд░ data_size рдХрдЪреНрдЪреЗ рдбреЗрдЯрд╛ рдХреА рд░рд╛рд╢рд┐ рд▓реМрдЯрд╛рддрд╛ рд╣реИред

рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рдбреЗрдЯрд╛ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо рддреБрд░рдВрдд рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд▓реМрдЯ рдЬрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рд╣рдореЗрдВ рдХрддрд╛рд░ рд╕реЗ рдЕрдзрд┐рдХ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдпрд╛ рд╣рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдЕрдЧрд░ рд╣рдореЗрдВ рдЕрднреА рднреА рдкреИрдХреЗрдЬ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЗрд╕реЗ рдЪрд┐рдкрдХрд╛ рджреЗрдВред рдпрджрд┐ рдЖрдкрдиреЗ рдкреИрдХреЗрдЬ рдкреВрд░рд╛ рдХрд░ рд▓рд┐рдпрд╛ рд╣реИ, рддреЛ рдЕрдВрдд рдореЗрдВ рдЗрд╕реЗ рдЬрд╛рд░реА рдХрд░реЗрдВред

рдФрд░ рдпрд╣ рд╕рдм рд╣реИ! рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдСрдбрд┐рдпреЛ рдХреЛ рдореБрдЦреНрдп рд░реАрдб рд▓реВрдк рд╕реЗ рдХрддрд╛рд░ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рддрдм рдСрдбрд┐рдпреЛ_ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рдкрдврд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ SDL рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ SDL рдЖрдкрдХреЗ рд╕рд╛рдЙрдВрдб рдХрд╛рд░реНрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЖрдЧреЗ рдмрдврд╝реЛ рдФрд░ рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВ:

gcc -o tutorial03 tutorial03.c -lavutil -lavformat -lavcodec -lswscale -lz -lm \
`sdl-config --cflags --libs`

GIP-GIP-рд╣реБрд░реНрд░реЗ! рд╡реАрдбрд┐рдпреЛ рдХреЛ рдЕрднреА рднреА рдЕрдзрд┐рдХрддрдо рдЧрддрд┐ рдкрд░ рд▓реЗ рдЬрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдзреНрд╡рдирд┐ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЦреЗрд▓ рд░рд╣реА рд╣реИ рдЬреИрд╕рд╛ рдХрд┐ рдЗрд╕реЗ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕рд╛ рдХреНрдпреЛрдВ рд╣реИ? рд╣рд╛рдВ, рдХреНрдпреЛрдВрдХрд┐ рдСрдбрд┐рдпреЛ рдЬрд╛рдирдХрд╛рд░реА рдореЗрдВ рдПрдХ рдирдореВрдирд╛ рдЖрд╡реГрддреНрддрд┐ рд╣реЛрддреА рд╣реИ - рд╣рдо рдСрдбрд┐рдпреЛ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдЙрддрдиреА рд╣реА рддреЗрдЬреА рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд╛рд▓рддреЗ рд╣реИрдВ, рдЬрд┐рддрдирд╛ рдХрд┐ рдпрд╣ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдСрдбрд┐рдпреЛ рдХреЗрд╡рд▓ рдЗрд╕ рдирдореВрдиреЗ рдореЗрдВ рдЗрд╕рдХреА рдирдореВрдирд╛ рдЖрд╡реГрддреНрддрд┐ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЦреЗрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╣рдо рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЗ рд▓рд┐рдП рд▓рдЧрднрдЧ рдкрд░рд┐рдкрдХреНрд╡ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкрд╣рд▓реЗ рд╣рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЗ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рдкреБрдирд░реНрдЧрдарди рдХреЛ рдЕрдВрдЬрд╛рдо рджреЗрдирд╛ рд╣реЛрдЧрд╛ред рд╕рд╛рдЙрдВрдб рдХреЛ рдХрддрд╛рд░рдмрджреНрдз рдХрд░рдиреЗ рдФрд░ рдПрдХ рдЕрд▓рдЧ рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рдЦреЗрд▓рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдиреЗ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд┐рдпрд╛: рдЗрд╕рдиреЗ рдХреЛрдб рдХреЛ рдЕрдзрд┐рдХ рдкреНрд░рдмрдВрдзрдиреАрдп рдФрд░ рдЕрдзрд┐рдХ рдореЙрдбреНрдпреВрд▓рд░ рдмрдирд╛ рджрд┐рдпрд╛ред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдСрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╡реАрдбрд┐рдпреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ, рд╣рдореЗрдВ рдХреЛрдб рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЕрдЧрд▓реА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдореЗрдВ рд╣рдо рдирд┐рдпрдВрддреНрд░рдг рдкреНрд░рд╡рд╛рд╣ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░реЗрдВрдЧреЗ!






рдЕрдзреНрдпрд╛рдп 4: рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдереНрд░реЗрдб тЖР тЗС тЖТ


рдкреВрд░реНрдг рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ tutorial04.c
// tutorial04.c
// A pedagogical video player that will stream through every video frame as fast as it can,
// and play audio (out of sync).
//
// Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, 
// and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
// With updates from https://github.com/chelyaev/ffmpeg-tutorial
// Updates tested on:
// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101, SDL 1.2.15
// on GCC 4.7.2 in Debian February 2015
// Use
//
// gcc -o tutorial04 tutorial04.c -lavformat -lavcodec -lswscale -lz -lm `sdl-config --cflags --libs`
// to build (assuming libavformat and libavcodec are correctly installed, 
// and assuming you have sdl-config. Please refer to SDL docs for your installation.)
//
// Run using
// tutorial04 myvideofile.mpg
//
// to play the video stream on your screen.

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <SDL.h>
#include <SDL_thread.h>

#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif

#include <stdio.h>
#include <assert.h>
#include <math.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

#define SDL_AUDIO_BUFFER_SIZE 1024
#define MAX_AUDIO_FRAME_SIZE 192000

#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)

#define FF_REFRESH_EVENT (SDL_USEREVENT)
#define FF_QUIT_EVENT (SDL_USEREVENT + 1)

#define VIDEO_PICTURE_QUEUE_SIZE 1

typedef struct PacketQueue {
  AVPacketList *first_pkt, *last_pkt;
  int nb_packets;
  int size;
  SDL_mutex *mutex;
  SDL_cond *cond;
} PacketQueue;


typedef struct VideoPicture {
  SDL_Overlay *bmp;
  int width, height; /* source height & width */
  int allocated;
} VideoPicture;

typedef struct VideoState {

  AVFormatContext *pFormatCtx;
  int             videoStream, audioStream;
  AVStream        *audio_st;
  AVCodecContext  *audio_ctx;
  PacketQueue     audioq;
  uint8_t         audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
  unsigned int    audio_buf_size;
  unsigned int    audio_buf_index;
  AVFrame         audio_frame;
  AVPacket        audio_pkt;
  uint8_t         *audio_pkt_data;
  int             audio_pkt_size;
  AVStream        *video_st;
  AVCodecContext  *video_ctx;
  PacketQueue     videoq;
  struct SwsContext *sws_ctx;

  VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];
  int             pictq_size, pictq_rindex, pictq_windex;
  SDL_mutex       *pictq_mutex;
  SDL_cond        *pictq_cond;
  
  SDL_Thread      *parse_tid;
  SDL_Thread      *video_tid;

  char            filename[1024];
  int             quit;
} VideoState;

SDL_Surface     *screen;
SDL_mutex       *screen_mutex;

/* Since we only have one decoding thread, the Big Struct
   can be global in case we need it. */
VideoState *global_video_state;

void packet_queue_init(PacketQueue *q) {
  memset(q, 0, sizeof(PacketQueue));
  q->mutex = SDL_CreateMutex();
  q->cond = SDL_CreateCond();
}
int packet_queue_put(PacketQueue *q, AVPacket *pkt) {

  AVPacketList *pkt1;
  if(av_dup_packet(pkt) < 0) {
    return -1;
  }
  pkt1 = av_malloc(sizeof(AVPacketList));
  if (!pkt1)
    return -1;
  pkt1->pkt = *pkt;
  pkt1->next = NULL;
  
  SDL_LockMutex(q->mutex);

  if (!q->last_pkt)
    q->first_pkt = pkt1;
  else
    q->last_pkt->next = pkt1;
  q->last_pkt = pkt1;
  q->nb_packets++;
  q->size += pkt1->pkt.size;
  SDL_CondSignal(q->cond);
  
  SDL_UnlockMutex(q->mutex);
  return 0;
}
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{
  AVPacketList *pkt1;
  int ret;

  SDL_LockMutex(q->mutex);
  
  for(;;) {
    
    if(global_video_state->quit) {
      ret = -1;
      break;
    }

    pkt1 = q->first_pkt;
    if (pkt1) {
      q->first_pkt = pkt1->next;
      if (!q->first_pkt)
	q->last_pkt = NULL;
      q->nb_packets--;
      q->size -= pkt1->pkt.size;
      *pkt = pkt1->pkt;
      av_free(pkt1);
      ret = 1;
      break;
    } else if (!block) {
      ret = 0;
      break;
    } else {
      SDL_CondWait(q->cond, q->mutex);
    }
  }
  SDL_UnlockMutex(q->mutex);
  return ret;
}

int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size) {

  int len1, data_size = 0;
  AVPacket *pkt = &is->audio_pkt;

  for(;;) {
    while(is->audio_pkt_size > 0) {
      int got_frame = 0;
      len1 = avcodec_decode_audio4(is->audio_ctx, &is->audio_frame, &got_frame, pkt);
      if(len1 < 0) {
	/* if error, skip frame */
	is->audio_pkt_size = 0;
	break;
      }
      data_size = 0;
      if(got_frame) {
	data_size = av_samples_get_buffer_size(NULL, 
					       is->audio_ctx->channels,
					       is->audio_frame.nb_samples,
					       is->audio_ctx->sample_fmt,
					       1);
	assert(data_size <= buf_size);
	memcpy(audio_buf, is->audio_frame.data[0], data_size);
      }
      is->audio_pkt_data += len1;
      is->audio_pkt_size -= len1;
      if(data_size <= 0) {
	/* No data yet, get more frames */
	continue;
      }
      /* We have data, return it and come back for more later */
      return data_size;
    }
    if(pkt->data)
      av_free_packet(pkt);

    if(is->quit) {
      return -1;
    }
    /* next packet */
    if(packet_queue_get(&is->audioq, pkt, 1) < 0) {
      return -1;
    }
    is->audio_pkt_data = pkt->data;
    is->audio_pkt_size = pkt->size;
  }
}

void audio_callback(void *userdata, Uint8 *stream, int len) {

  VideoState *is = (VideoState *)userdata;
  int len1, audio_size;

  while(len > 0) {
    if(is->audio_buf_index >= is->audio_buf_size) {
      /* We have already sent all our data; get more */
      audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf));
      if(audio_size < 0) {
	/* If error, output silence */
	is->audio_buf_size = 1024;
	memset(is->audio_buf, 0, is->audio_buf_size);
      } else {
	is->audio_buf_size = audio_size;
      }
      is->audio_buf_index = 0;
    }
    len1 = is->audio_buf_size - is->audio_buf_index;
    if(len1 > len)
      len1 = len;
    memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
    len -= len1;
    stream += len1;
    is->audio_buf_index += len1;
  }
}

static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {
  SDL_Event event;
  event.type = FF_REFRESH_EVENT;
  event.user.data1 = opaque;
  SDL_PushEvent(&event);
  return 0; /* 0 means stop timer */
}

/* schedule a video refresh in 'delay' ms */
static void schedule_refresh(VideoState *is, int delay) {
  SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
}

void video_display(VideoState *is) {

  SDL_Rect rect;
  VideoPicture *vp;
  float aspect_ratio;
  int w, h, x, y;
  int i;

  vp = &is->pictq[is->pictq_rindex];
  if(vp->bmp) {
    if(is->video_ctx->sample_aspect_ratio.num == 0) {
      aspect_ratio = 0;
    } else {
      aspect_ratio = av_q2d(is->video_ctx->sample_aspect_ratio) *
	is->video_ctx->width / is->video_ctx->height;
    }
    if(aspect_ratio <= 0.0) {
      aspect_ratio = (float)is->video_ctx->width /
	(float)is->video_ctx->height;
    }
    h = screen->h;
    w = ((int)rint(h * aspect_ratio)) & -3;
    if(w > screen->w) {
      w = screen->w;
      h = ((int)rint(w / aspect_ratio)) & -3;
    }
    x = (screen->w - w) / 2;
    y = (screen->h - h) / 2;
    
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_LockMutex(screen_mutex);
    SDL_DisplayYUVOverlay(vp->bmp, &rect);
    SDL_UnlockMutex(screen_mutex);

  }
}

void video_refresh_timer(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;
  
  if(is->video_st) {
    if(is->pictq_size == 0) {
      schedule_refresh(is, 1);
    } else {
      vp = &is->pictq[is->pictq_rindex];
      /* Now, normally here goes a ton of code
	 about timing, etc. we're just going to
	 guess at a delay for now. You can
	 increase and decrease this value and hard code
	 the timing - but I don't suggest that ;)
	 We'll learn how to do it for real later.
      */
      schedule_refresh(is, 40);
      
      /* show the picture! */
      video_display(is);
      
      /* update queue for next picture! */
      if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {
	is->pictq_rindex = 0;
      }
      SDL_LockMutex(is->pictq_mutex);
      is->pictq_size--;
      SDL_CondSignal(is->pictq_cond);
      SDL_UnlockMutex(is->pictq_mutex);
    }
  } else {
    schedule_refresh(is, 100);
  }
}
      
void alloc_picture(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;

  vp = &is->pictq[is->pictq_windex];
  if(vp->bmp) {
    // we already have one make another, bigger/smaller
    SDL_FreeYUVOverlay(vp->bmp);
  }
  // Allocate a place to put our YUV image on that screen
  SDL_LockMutex(screen_mutex);
  vp->bmp = SDL_CreateYUVOverlay(is->video_ctx->width,
				 is->video_ctx->height,
				 SDL_YV12_OVERLAY,
				 screen);
  SDL_UnlockMutex(screen_mutex);

  vp->width = is->video_ctx->width;
  vp->height = is->video_ctx->height;
  vp->allocated = 1;

}

int queue_picture(VideoState *is, AVFrame *pFrame) {

  VideoPicture *vp;
  int dst_pix_fmt;
  AVPicture pict;

  /* wait until we have space for a new pic */
  SDL_LockMutex(is->pictq_mutex);
  while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
	!is->quit) {
    SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  }
  SDL_UnlockMutex(is->pictq_mutex);

  if(is->quit)
    return -1;

  // windex is set to 0 initially
  vp = &is->pictq[is->pictq_windex];

  /* allocate or resize the buffer! */
  if(!vp->bmp ||
     vp->width != is->video_ctx->width ||
     vp->height != is->video_ctx->height) {
    SDL_Event event;

    vp->allocated = 0;
    alloc_picture(is);
    if(is->quit) {
      return -1;
    }
  }

  /* We have a place to put our picture on the queue */

  if(vp->bmp) {

    SDL_LockYUVOverlay(vp->bmp);
    
    dst_pix_fmt = PIX_FMT_YUV420P;
    /* point pict at the queue */

    pict.data[0] = vp->bmp->pixels[0];
    pict.data[1] = vp->bmp->pixels[2];
    pict.data[2] = vp->bmp->pixels[1];
    
    pict.linesize[0] = vp->bmp->pitches[0];
    pict.linesize[1] = vp->bmp->pitches[2];
    pict.linesize[2] = vp->bmp->pitches[1];
    
    // Convert the image into YUV format that SDL uses
    sws_scale(is->sws_ctx, (uint8_t const * const *)pFrame->data,
	      pFrame->linesize, 0, is->video_ctx->height,
	      pict.data, pict.linesize);
    
    SDL_UnlockYUVOverlay(vp->bmp);
    /* now we inform our display thread that we have a pic ready */
    if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) {
      is->pictq_windex = 0;
    }
    SDL_LockMutex(is->pictq_mutex);
    is->pictq_size++;
    SDL_UnlockMutex(is->pictq_mutex);
  }
  return 0;
}

int video_thread(void *arg) {
  VideoState *is = (VideoState *)arg;
  AVPacket pkt1, *packet = &pkt1;
  int frameFinished;
  AVFrame *pFrame;

  pFrame = av_frame_alloc();

  for(;;) {
    if(packet_queue_get(&is->videoq, packet, 1) < 0) {
      // means we quit getting packets
      break;
    }
    // Decode video frame
    avcodec_decode_video2(is->video_ctx, pFrame, &frameFinished, packet);
    // Did we get a video frame?
    if(frameFinished) {
      if(queue_picture(is, pFrame) < 0) {
	break;
      }      
    }
    av_free_packet(packet);
  }
  av_frame_free(&pFrame);
  return 0;
}

int stream_component_open(VideoState *is, int stream_index) {

  AVFormatContext *pFormatCtx = is->pFormatCtx;
  AVCodecContext *codecCtx = NULL;
  AVCodec *codec = NULL;
  SDL_AudioSpec wanted_spec, spec;

  if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) {
    return -1;
  }

  codec = avcodec_find_decoder(pFormatCtx->streams[stream_index]->codec->codec_id);
  if(!codec) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  codecCtx = avcodec_alloc_context3(codec);
  if(avcodec_copy_context(codecCtx, pFormatCtx->streams[stream_index]->codec) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }


  if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) {
    // Set audio settings from codec info
    wanted_spec.freq = codecCtx->sample_rate;
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.channels = codecCtx->channels;
    wanted_spec.silence = 0;
    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
    wanted_spec.callback = audio_callback;
    wanted_spec.userdata = is;
    
    if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {
      fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
      return -1;
    }
  }
  if(avcodec_open2(codecCtx, codec, NULL) < 0) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  switch(codecCtx->codec_type) {
  case AVMEDIA_TYPE_AUDIO:
    is->audioStream = stream_index;
    is->audio_st = pFormatCtx->streams[stream_index];
    is->audio_ctx = codecCtx;
    is->audio_buf_size = 0;
    is->audio_buf_index = 0;
    memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
    packet_queue_init(&is->audioq);
    SDL_PauseAudio(0);
    break;
  case AVMEDIA_TYPE_VIDEO:
    is->videoStream = stream_index;
    is->video_st = pFormatCtx->streams[stream_index];
    is->video_ctx = codecCtx;
    packet_queue_init(&is->videoq);
    is->video_tid = SDL_CreateThread(video_thread, is);
    is->sws_ctx = sws_getContext(is->video_ctx->width, is->video_ctx->height,
				 is->video_ctx->pix_fmt, is->video_ctx->width,
				 is->video_ctx->height, PIX_FMT_YUV420P,
				 SWS_BILINEAR, NULL, NULL, NULL
				 );
    break;
  default:
    break;
  }
}

int decode_thread(void *arg) {

  VideoState *is = (VideoState *)arg;
  AVFormatContext *pFormatCtx;
  AVPacket pkt1, *packet = &pkt1;

  int video_index = -1;
  int audio_index = -1;
  int i;

  is->videoStream=-1;
  is->audioStream=-1;

  global_video_state = is;

  // Open video file
  if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0)
    return -1; // Couldn't open file

  is->pFormatCtx = pFormatCtx;
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, is->filename, 0);
  
  // Find the first video stream

  for(i=0; i<pFormatCtx->nb_streams; i++) {
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO &&
       video_index < 0) {
      video_index=i;
    }
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&
       audio_index < 0) {
      audio_index=i;
    }
  }
  if(audio_index >= 0) {
    stream_component_open(is, audio_index);
  }
  if(video_index >= 0) {
    stream_component_open(is, video_index);
  }   

  if(is->videoStream < 0 || is->audioStream < 0) {
    fprintf(stderr, "%s: could not open codecs\n", is->filename);
    goto fail;
  }

  // main decode loop

  for(;;) {
    if(is->quit) {
      break;
    }
    // seek stuff goes here
    if(is->audioq.size > MAX_AUDIOQ_SIZE ||
       is->videoq.size > MAX_VIDEOQ_SIZE) {
      SDL_Delay(10);
      continue;
    }
    if(av_read_frame(is->pFormatCtx, packet) < 0) {
      if(is->pFormatCtx->pb->error == 0) {
	SDL_Delay(100); /* no error; wait for user input */
	continue;
      } else {
	break;
      }
    }
    // Is this a packet from the video stream?
    if(packet->stream_index == is->videoStream) {
      packet_queue_put(&is->videoq, packet);
    } else if(packet->stream_index == is->audioStream) {
      packet_queue_put(&is->audioq, packet);
    } else {
      av_free_packet(packet);
    }
  }
  /* all done - wait for it */
  while(!is->quit) {
    SDL_Delay(100);
  }

 fail:
  if(1){
    SDL_Event event;
    event.type = FF_QUIT_EVENT;
    event.user.data1 = is;
    SDL_PushEvent(&event);
  }
  return 0;
}

int main(int argc, char *argv[]) {

  SDL_Event       event;

  VideoState      *is;

  is = av_mallocz(sizeof(VideoState));

  if(argc < 2) {
    fprintf(stderr, "Usage: test <file>\n");
    exit(1);
  }
  // Register all formats and codecs
  av_register_all();
  
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    exit(1);
  }

  // Make a screen to put our video
#ifndef __DARWIN__
        screen = SDL_SetVideoMode(640, 480, 0, 0);
#else
        screen = SDL_SetVideoMode(640, 480, 24, 0);
#endif
  if(!screen) {
    fprintf(stderr, "SDL: could not set video mode - exiting\n");
    exit(1);
  }

  screen_mutex = SDL_CreateMutex();

  av_strlcpy(is->filename, argv[1], sizeof(is->filename));

  is->pictq_mutex = SDL_CreateMutex();
  is->pictq_cond = SDL_CreateCond();

  schedule_refresh(is, 40);

  is->parse_tid = SDL_CreateThread(decode_thread, is);
  if(!is->parse_tid) {
    av_free(is);
    return -1;
  }
  for(;;) {

    SDL_WaitEvent(&event);
    switch(event.type) {
    case FF_QUIT_EVENT:
    case SDL_QUIT:
      is->quit = 1;
      SDL_Quit();
      return 0;
      break;
    case FF_REFRESH_EVENT:
      video_refresh_timer(event.user.data1);
      break;
    default:
      break;
    }
  }
  return 0;

}

рдЕрд╡рд▓реЛрдХрди


рдкрд┐рдЫрд▓реА рдмрд╛рд░, рд╣рдордиреЗ SDL рдСрдбрд┐рдпреЛ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдСрдбрд┐рдпреЛ рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рд╛ рдерд╛ред рдПрд╕рдбреАрдПрд▓ рдиреЗ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдереНрд░реЗрдб рдмрдирд╛рдиреЗ рд╡рд╛рд▓реА рдХреЙрд▓рдмреИрдХ рд▓реЙрдиреНрдЪ рдХреА рдЬрд┐рд╕реЗ рд╣рдордиреЗ рд╣рд░ рдмрд╛рд░ рдзреНрд╡рдирд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдерд╛ред рдЕрдм рд╣рдо рд╡реАрдбрд┐рдпреЛ рдбрд┐рд╕реНрдкреНрд▓реЗ рдХреЗ рд╕рд╛рде рднреА рдРрд╕рд╛ рд╣реА рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рдпрд╣ рдХреЛрдб рдХреЛ рдЕрдзрд┐рдХ рдореЙрдбреНрдпреВрд▓рд░ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реЛрддрд╛ рд╣реИ - рдЦрд╛рд╕рдХрд░ рдпрджрд┐ рдЖрдк рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рддреЛ рд╣рдо рдХрд╣рд╛рдВ рд╕реЗ рд╢реБрд░реВ рдХрд░реЗрдВ?

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдорд╛рд░рд╛ рдореБрдЦреНрдп рдХрд╛рд░реНрдп рдмрд╣реБрдд рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ: рдпрд╣ рдЗрд╡реЗрдВрдЯ рд▓реВрдк рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рддрд╛ рд╣реИ, рдкреИрдХреЗрдЯ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рд╡реАрдбрд┐рдпреЛ рдХреЛ рдбреАрдХреЛрдб рдХрд░рддрд╛ рд╣реИред рд╣рдо рдЬреЛ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рд╡рд╣ рд╕рдм рдХреБрдЫ рднрд╛рдЧреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдирд╛ рд╣реИ: рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдбрд┐рдХреЛрдбрд┐рдВрдЧ рдкреИрдХреЗрдЯ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рдзрд╛рд░рд╛ рд╣реЛрдЧреА; рдлрд┐рд░ рдЗрди рдкреИрдХреЗрдЯреЛрдВ рдХреЛ рдХрддрд╛рд░ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рджреНрд╡рд╛рд░рд╛ рдкрдврд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рдЖрд╡рд╢реНрдпрдХрддрд╛рдиреБрд╕рд╛рд░ рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреЛ рдЯреНрдпреВрди рдХрд░ рд▓рд┐рдпрд╛ рд╣реИ; рдПрдХ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреЗ рд╕рд╛рде рдпрд╣ рдХреБрдЫ рдФрд░ рдХрдард┐рди рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рд╡реАрдбрд┐рдпреЛ рд╣рдорд╛рд░реЗ рджрдо рдкрд░ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рджрд░реНрд╢рди рдХреЛрдб рдХреЛ рдореБрдЦреНрдп рд▓реВрдк рдореЗрдВ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗред рд▓реЗрдХрд┐рди рд╣рд░ рдмрд╛рд░ рдЬрдм рд╣рдо рд▓реВрдк рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╡реАрдбрд┐рдпреЛ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рд╡реАрдбрд┐рдпреЛ рдбрд┐рд╕реНрдкреНрд▓реЗ рдХреЛ рдЗрд╡реЗрдВрдЯ рд▓реВрдк рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд░рддреЗ рд╣реИрдВред рд╡реАрдбрд┐рдпреЛ рдХреЛ рдбрд┐рдХреЛрдб рдХрд░рдиреЗ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ, рдкреНрд░рд╛рдкреНрдд рдлреНрд░реЗрдо рдХреЛ рджреВрд╕рд░реА рдХрддрд╛рд░ рдореЗрдВ рд╕рд╣реЗрдЬреЗрдВ, рдлрд┐рд░ рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рдИрд╡реЗрдВрдЯ рдмрдирд╛рдПрдВ ( FF_REFRESH_EVENT), рдЬрд┐рд╕реЗ рд╣рдо рдИрд╡реЗрдВрдЯ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рддрдм рдЬрдм рд╣рдорд╛рд░рд╛ рдИрд╡реЗрдВрдЯ рд▓реВрдк рдЗрд╕ рдИрд╡реЗрдВрдЯ рдХреЛ рджреЗрдЦрддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдХрддрд╛рд░ рдореЗрдВ рдЕрдЧрд▓рд╛ рдлрд╝реНрд░реЗрдо рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ред рдпрд╣рд╛рдВ рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ ASCII рдЪрд┐рддреНрд░рдг рд╣реИ рдЬреЛ рд╣реЛ рд░рд╣рд╛ рд╣реИ:


рдЗрд╡реЗрдВрдЯ рд▓реВрдк рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡реАрдбрд┐рдпреЛ рдбрд┐рд╕реНрдкреНрд▓реЗ рдХрдВрдЯреНрд░реЛрд▓ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдореБрдЦреНрдп рдХрд╛рд░рдг рдпрд╣ рд╣реИ рдХрд┐ SDL_Delay рд╕реНрдЯреНрд░реАрдо рдХреЗ рд╕рд╛рде рд╣рдо рд╕реНрдХреНрд░реАрди рдкрд░ рдЕрдЧрд▓рд╛ рд╡реАрдбрд┐рдпреЛ рдлреНрд░реЗрдо рджрд┐рдЦрд╛рдИ рджреЗрдиреЗ рдкрд░ рдареАрдХ рд╕реЗ рдирд┐рдпрдВрддреНрд░рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЬрдм рд╣рдо рдЕрдВрдд рдореЗрдВ рдЕрдЧрд▓реЗ рдкрд╛рда рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдмрд╕ рдПрдХ рдХреЛрдб рдЬреЛрдбрд╝реЗрдВ рдЬреЛ рдЕрдЧрд▓реЗ рд╡реАрдбрд┐рдпреЛ рдЕрдкрдбреЗрдЯ рдХреЛ рд╢реЗрдбреНрдпреВрд▓ рдХрд░реЗрдЧрд╛ рддрд╛рдХрд┐ рд╕рд╣реА рдЫрд╡рд┐ рд╕рд╣реА рд╕рдордп рдкрд░ рд╕реНрдХреНрд░реАрди рдкрд░ рджрд┐рдЦрд╛рдИ рджреЗред

рдХреЛрдб рдХреЛ рд╕рд░рд▓ рдХреАрдЬрд┐рдП


рдХреЛрдб рдХреЛ рдереЛрдбрд╝рд╛ рдХреНрд▓рд┐рдпрд░ рдХрд░рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рдХреЛрдбреЗрдХреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╣ рд╕рдм рдЬрд╛рдирдХрд╛рд░реА рд╣реИ, рдФрд░ рд╣рдо рдХрддрд╛рд░реЛрдВ, рдмрдлрд╝рд░реНрд╕ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдФрд░ рднрдЧрд╡рд╛рди рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдФрд░ рдХреНрдпрд╛ рд╣реИред рдпреЗ рд╕рднреА рдЪреАрдЬреЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рддрд╛рд░реНрдХрд┐рдХ рдЗрдХрд╛рдИ рдХреЗ рд▓рд┐рдП рд╣реИрдВ, рдЕрд░реНрдерд╛рддреН - рдлрд┐рд▓реНрдо рдХреЗ рд▓рд┐рдПред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдПрдХ рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдиреЗ рдХрд╛ рдЗрд░рд╛рджрд╛ рд░рдЦрддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ VideoState рдирд╛рдордХ рдпрд╣ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рд╣реЛ ред

typedef struct VideoState {

  AVFormatContext *pFormatCtx;
  int             videoStream, audioStream;
  AVStream        *audio_st;
  AVCodecContext  *audio_ctx;
  PacketQueue     audioq;
  uint8_t         audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
  unsigned int    audio_buf_size;
  unsigned int    audio_buf_index;
  AVPacket        audio_pkt;
  uint8_t         *audio_pkt_data;
  int             audio_pkt_size;
  AVStream        *video_st;
  AVCodecContext  *video_ctx;
  PacketQueue     videoq;

  VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];
  int             pictq_size, pictq_rindex, pictq_windex;
  SDL_mutex       *pictq_mutex;
  SDL_cond        *pictq_cond;
  
  SDL_Thread      *parse_tid;
  SDL_Thread      *video_tid;

  char            filename[1024];
  int             quit;
} VideoState;

рдпрд╣рд╛рдБ рд╣рдо рдЕрдВрдд рдореЗрдВ рдЬреЛ рдкрд╛рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдЙрд╕рдХреЗ рд╕рдВрдХреЗрдд рджреЗрдЦрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдмреБрдирд┐рдпрд╛рджреА рдЬрд╛рдирдХрд╛рд░реА - рдкреНрд░рд╛рд░реВрдк рд╕рдВрджрд░реНрдн рдФрд░ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд╕реВрдЪрдХрд╛рдВрдХреЛрдВ, рд╕рд╛рде рд╣реА рд╕рдВрдмрдВрдзрд┐рдд AVStream рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ ред рдлрд┐рд░ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдЗрдирдореЗрдВ рд╕реЗ рдХреБрдЫ рдСрдбрд┐рдпреЛ рдмрдлрд╝рд░реНрд╕ рдХреЛ рдЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рд▓реЗ рдЬрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╡реЗ ( Audio_buf , audio_buf_size , рдЖрджрд┐) рдСрдбрд┐рдпреЛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП рдЕрднрд┐рдкреНрд░реЗрдд рдереЗ рдЬреЛ рдЕрднреА рднреА рд╡рд╣рд╛рдБ рдерд╛ (рдпрд╛ рдЧрд╛рдпрдм рдерд╛)ред рд╣рдордиреЗ рд╡реАрдбрд┐рдпреЛ рдФрд░ рдПрдХ рдмрдлрд╝рд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рдХрддрд╛рд░ рдЬреЛрдбрд╝реА (рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рдХрддрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛; рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рдбреАрдХреЛрдбреЗрдб рдлрд╝реНрд░реЗрдореНрд╕ (рдУрд╡рд░рд▓реЗ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рд╣реЗрдЬреЗ рдЧрдП) рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рдЕрддрд┐рд░рд┐рдХреНрдд рдХрддрд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ)ред рд╡реАрдбрд┐рдпреЛрдЪрд┐рддреНрд░ рд╕рдВрд░рдЪрдирд╛- рдпрд╣ рд╣рдорд╛рд░реА рдЕрдкрдиреА рд░рдЪрдирд╛ рд╣реИ (рдЬрдм рд╣рдо рдЗрд╕рдХреЗ рдкрд╛рд╕ рдЖрдПрдВрдЧреЗ рддреЛ рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдЗрд╕рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрдЧрд╛)ред рдЖрдк рдпрд╣ рднреА рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдордиреЗ рджреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдзрд╛рд░рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдкреЙрдЗрдВрдЯрд░реНрд╕ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдП рд╣реИрдВ рдЬреЛ рд╣рдо рдмрдирд╛рдПрдВрдЧреЗ, рд╕рд╛рде рд╣реА рдПрдХ рдПрдХреНрдЬрд╝рд┐рдЯ рдлрд╝реНрд▓реИрдЧ рдФрд░ рдПрдХ рдореВрд╡реА рдлрд╝рд╛рдЗрд▓ рдирд╛рдо рднреАред

рдЗрд╕рд▓рд┐рдП, рдЕрдм рд╣рдо рдореБрдЦреНрдп рдлрд╝рдВрдХреНрд╢рди рдкрд░ рд▓реМрдЯрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХреЗ рдХрд┐ рдпрд╣ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдХреИрд╕реЗ рдмрджрд▓рддрд╛ рд╣реИред рдЖрдЗрдП рд╣рдо рдЕрдкрдиреА VideoState рд╕рдВрд░рдЪрдирд╛ рд╕реЗрдЯ рдХрд░реЗрдВ :

int main(int argc, char *argv[]) {

  SDL_Event       event;

  VideoState      *is;

  is = av_mallocz(sizeof(VideoState));

av_mallocz () рдПрдХ рдЕрдЪреНрдЫрд╛ рдХрд╛рд░реНрдп рд╣реИ рдЬреЛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░реЗрдЧрд╛ рдФрд░ рдЗрд╕реЗ рд╢реВрдиреНрдп рдХрд░реЗрдЧрд╛ред

рдлрд┐рд░ рд╣рдо рдбрд┐рд╕реНрдкреНрд▓реЗ рдмрдлрд╝рд░ ( рдкреЛрд░реНрдЯрдХ ) рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рддрд╛рд▓реЗ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ , рдХреНрдпреЛрдВрдХрд┐ рдЪреВрдВрдХрд┐ рдИрд╡реЗрдВрдЯ рд▓реВрдк рд╣рдорд╛рд░реЗ рдбрд┐рд╕реНрдкреНрд▓реЗ рдлрдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ - рдпрд╛рдж рд░рдЦреЗрдВ, рдбрд┐рд╕реНрдкреНрд▓реЗ рдлрдВрдХреНрд╢рди рдкрд┐рдХреНрдЯрдХ рд╕реЗ рдкреНрд░реА-рдбрд┐рдХреЛрдбреЗрдб рдлреНрд░реЗрдо рдХреЛ рдкреБрдирдГ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧрд╛ ред рдЙрд╕реА рд╕рдордп, рд╣рдорд╛рд░рд╛ рд╡реАрдбрд┐рдпреЛ рдбрд┐рдХреЛрдбрд░ рдЗрд╕рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдбрд╛рд▓реЗрдЧрд╛ - рд╣рдо рдирд╣реАрдВ рдЬрд╛рдирддреЗ рдХрд┐ рдкрд╣рд▓реЗ рдХреМрди рд╡рд╣рд╛рдВ рдкрд╣реБрдВрдЪрддрд╛ рд╣реИред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЖрдк рд╕рдордЭ рдЧрдП рд╣реЛрдВрдЧреЗ рдХрд┐ рдпрд╣ рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рджреМрдбрд╝ рдХреА рд╕реНрдерд┐рддрд┐ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдХрд┐рд╕реА рднреА рд╡рд┐рд╖рдп рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЗрд╕реЗ рд╡рд┐рддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдЪрд▓рд┐рдП рд╣рдорд╛рд░реА рдлрд┐рд▓реНрдо рдХреЗ рдирд╛рдо рдХреЛ рднреА рд╡реАрдбрд┐рдпреЛрд╕реНрдЯреЗрдЯ рдореЗрдВ рдХреЙрдкреА рдХрд░рддреЗ рд╣реИрдВ :

av_strlcpy(is->filename, argv[1], sizeof(is->filename));

is->pictq_mutex = SDL_CreateMutex();
is->pictq_cond = SDL_CreateCond();

av_strlcpy FFmpeg рдХрд╛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдмреЙрд░реНрдбрд░ рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ strncpy ред

рд╣рдорд╛рд░рд╛ рдкрд╣рд▓рд╛ рд╕реВрддреНрд░


рдЪрд▓реЛ рд╣рдорд╛рд░реЗ рдзрд╛рдЧреЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВ рдФрд░ рдХреБрдЫ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ:

schedule_refresh(is, 40);

is->parse_tid = SDL_CreateThread(decode_thread, is);
if(!is->parse_tid) {
  av_free(is);
  return -1;
}

Schedule_refresh рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдмрд╛рдж рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВрдЧреЗред рд╡рд╣ рдЬреЛ рдмрддрд╛рддреА рд╣реИ, рд╡рд╣ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреЗ рдмрд╛рдж FF_REFRESH_EVENT рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдгрд╛рд▓реА рд╣реИ ред рдпрд╣, рдмрджрд▓реЗ рдореЗрдВ, рд╡реАрдбрд┐рдпреЛ рдЕрдкрдбреЗрдЯ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ рдЬрдм рд╣рдо рдЗрд╕реЗ рдШрдЯрдирд╛ рдХрддрд╛рд░ рдореЗрдВ рджреЗрдЦрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЕрдм SDL_CreateThread () рджреЗрдЦреЗрдВред

SDL_CreateThread () рдмрд╕ рдпрд╣реА рдХрд░рддрд╛ рд╣реИ - рдпрд╣ рдПрдХ рдирдП рдереНрд░реЗрдб рдХреЛ рдЬрдиреНрдо рджреЗрддрд╛ рд╣реИ рдЬрд┐рд╕рдХреА рдореВрд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рд╕рднреА рдореЗрдореЛрд░реА рддрдХ рдкреВрд░реА рдкрд╣реБрдВрдЪ рд╣реИ, рдФрд░ рдЬрд┐рд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд╣рдо рджреЗрддреЗ рд╣реИрдВ, рдЙрд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдереНрд░реЗрдб рдХреЛ рдкреНрд░рд╛рд░рдВрдн рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдкрд░рд┐рднрд╛рд╖рд┐рдд рдбреЗрдЯрд╛ рднреА рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░реЗрдЧрд╛ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдо рдбрд┐рдХреЛрдб_рдереНрд░реЗрдб () рдХрд╣рддреЗ рд╣реИрдВ рдФрд░ рд╣рдорд╛рд░реА рд╡реАрдбрд┐рдпреЛрд╕реНрдЯреЗрдЯ рд╕рдВрд░рдЪрдирд╛ рдХреЛ рд╕рдВрд▓рдЧреНрди рдХрд░рддреЗ рд╣реИрдВред рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдкрд╣рд▓реЗ рдЫрдорд╛рд╣реА рдореЗрдВ рдХреБрдЫ рднреА рдирдпрд╛ рдирд╣реАрдВ рд╣реИ; рдпрд╣ рд╕рд┐рд░реНрдл рдлрд╝рд╛рдЗрд▓ рдЦреЛрд▓рдиреЗ рдФрд░ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдХреЗ рд╕реВрдЪрдХрд╛рдВрдХ рдХреЛ рдЦреЛрдЬрдиреЗ рдХрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдЬреЛ рд╣рдо рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдХрд░рддреЗ рд╣реИрдВ рд╡рд╣ рд╣реИ рдкреНрд░рд╛рд░реВрдк рдХреЛ рд╣рдорд╛рд░реА рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рд░рдЦрдирд╛ред рдЕрдкрдиреЗ рд╕реНрдЯреНрд░реАрдо рдЗрдВрдбреЗрдХреНрд╕ рдкрд╛рдП рдЬрд╛рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдПрдХ рдФрд░ рдлрд╝рдВрдХреНрд╢рди рдХрд╣рддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рд╣рдо рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, stream_component_open ()ред рдпрд╣ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рдлреА рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рддрд░реАрдХрд╛ рд╣реИ, рдФрд░ рдЪреВрдВрдХрд┐ рд╣рдо рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рдХреЛрдбреЗрдХ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╕реА рд╕рдорд╛рди рдЪреАрдЬреЗрдВ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдХреБрдЫ рдХреЛрдб рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдмрди рдЬрд╛рддрд╛ рд╣реИред Stream_component_open

рдлрд╝рдВрдХреНрд╢рди() рд╡рд╣ рд╕реНрдерд╛рди рд╣реИ рдЬрд╣рд╛рдВ рд╣рдо рдЕрдкрдиреЗ рдХреЛрдбреЗрдХ рдбрд┐рдХреЛрдбрд░ рдХреА рдЦреЛрдЬ рдХрд░рддреЗ рд╣реИрдВ, рдзреНрд╡рдирд┐ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреЗ рд╣реИрдВ, рд╣рдорд╛рд░реЗ рдмрдбрд╝реЗ рдврд╛рдВрдЪреЗ рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд╕рд╣реЗрдЬрддреЗ рд╣реИрдВ рдФрд░ рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд▓реЙрдиреНрдЪ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣рд╛рдВ рд╣рдо рдЕрдиреНрдп рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рднреА рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ рдЗрд╕рдХреЗ рд╕реНрд╡рдд: рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдХреЛрдбреЗрдХ рдХрд╛ рдЬрдмрд░рди рдЙрдкрдпреЛрдЧ рдЖрджрд┐ред рдРрд╢реЗ рд╣реА:

int stream_component_open(VideoState *is, int stream_index) {

  AVFormatContext *pFormatCtx = is->pFormatCtx;
  AVCodecContext *codecCtx;
  AVCodec *codec;
  SDL_AudioSpec wanted_spec, spec;

  if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) {
    return -1;
  }

  codec = avcodec_find_decoder(pFormatCtx->streams[stream_index]->codec->codec_id);
  if(!codec) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  codecCtx = avcodec_alloc_context3(codec);
  if(avcodec_copy_context(codecCtx, pFormatCtx->streams[stream_index]->codec) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }


  if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) {
    // Set audio settings from codec info
    wanted_spec.freq = codecCtx->sample_rate;
    /* ...etc... */
    wanted_spec.callback = audio_callback;
    wanted_spec.userdata = is;
    
    if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {
      fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
      return -1;
    }
  }
  if(avcodec_open2(codecCtx, codec, NULL) < 0) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  switch(codecCtx->codec_type) {
  case AVMEDIA_TYPE_AUDIO:
    is->audioStream = stream_index;
    is->audio_st = pFormatCtx->streams[stream_index];
    is->audio_ctx = codecCtx;
    is->audio_buf_size = 0;
    is->audio_buf_index = 0;
    memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
    packet_queue_init(&is->audioq);
    SDL_PauseAudio(0);
    break;
  case AVMEDIA_TYPE_VIDEO:
    is->videoStream = stream_index;
    is->video_st = pFormatCtx->streams[stream_index];
    is->video_ctx = codecCtx;
    
    packet_queue_init(&is->videoq);
    is->video_tid = SDL_CreateThread(video_thread, is);
    is->sws_ctx = sws_getContext(is->video_st->codec->width, is->video_st->codec->height,
				 is->video_st->codec->pix_fmt, is->video_st->codec->width,
				 is->video_st->codec->height, PIX_FMT_YUV420P,
				 SWS_BILINEAR, NULL, NULL, NULL
				 );
    break;
  default:
    break;
  }
}

рдпрд╣ рд▓рдЧрднрдЧ рдЙрд╕ рдХреЛрдб рдХреЗ рд╕рдорд╛рди рд╣реИ рдЬреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рдерд╛, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЕрдм рдпрд╣ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рд╣реИред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ aCodecCtx рдХреЗ рдмрдЬрд╛рдп , рд╣рдордиреЗ рдЕрдкрдиреА рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдЕрдкрдиреЗ рдСрдбрд┐рдпреЛ рдХреЙрд▓рдмреИрдХ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рд╣реИред рд╣рдордиреЗ рд╕реНрд╡рдпрдВ рд╕реНрдЯреНрд░реАрдо рдХреЛ рдСрдбрд┐рдпреЛ_рд╕реНрдЯ рдФрд░ рд╡реАрдбрд┐рдпреЛ_рд╕реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рд╣реЗрдЬрд╛ рд╣реИ ред рд╣рдордиреЗ рдЕрдкрдиреА рд╡реАрдбрд┐рдпреЛ рдХрддрд╛рд░ рднреА рдЬреЛрдбрд╝реА рдФрд░ рдЗрд╕реЗ рд╣рдорд╛рд░реА рдСрдбрд┐рдпреЛ рдХрддрд╛рд░ рдХреА рддрд░рд╣ рд╕реЗрдЯ рдХрд┐рдпрд╛ред рд▓рдмреНрдмреЛрд▓реБрдЖрдм рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИред рдпреЗ рдмрд┐рдЯреНрд╕ рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ:

    SDL_PauseAudio(0);
    break;

/* ...... */

    is->video_tid = SDL_CreateThread(video_thread, is);

SDL_PauseAudio () рдХреЛ рдЕрдВрддрд┐рдо рдкрд╛рда рд╕реЗ рдпрд╛рдж рд░рдЦреЗрдВ ред SDL_CreateThread () рдХрд╛ рдЙрдкрдпреЛрдЧ рдЙрд╕реА рддрд░рд╣ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ video_thread () рдлрд╝рдВрдХреНрд╢рди рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ ред

рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ, рдЪрд▓реЛ рд╣рдорд╛рд░реЗ рдбрд┐рдХреЛрдб_рдереНрд░реЗрдб () рдлрд╝рдВрдХреНрд╢рди рдХреЗ рджреВрд╕рд░реЗ рдЫрдорд╛рд╣реА рдореЗрдВ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ ред рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ, рдпрд╣ рд╕рд┐рд░реНрдл рдПрдХ рд▓реВрдк рдХреЗ рд▓рд┐рдП рд╣реИ рдЬреЛ рдПрдХ рдкреИрдХреЗрдЬ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕рд╣реА рдХрддрд╛рд░ рдореЗрдВ рд░рдЦрддрд╛ рд╣реИ:

  for(;;) {
    if(is->quit) {
      break;
    }
    // seek stuff goes here
    if(is->audioq.size > MAX_AUDIOQ_SIZE ||
       is->videoq.size > MAX_VIDEOQ_SIZE) {
      SDL_Delay(10);
      continue;
    }
    if(av_read_frame(is->pFormatCtx, packet) < 0) {
      if((is->pFormatCtx->pb->error) == 0) {
	SDL_Delay(100); /* no error; wait for user input */
	continue;
      } else {
	break;
      }
    }
    // Is this a packet from the video stream?
    if(packet->stream_index == is->videoStream) {
      packet_queue_put(&is->videoq, packet);
    } else if(packet->stream_index == is->audioStream) {
      packet_queue_put(&is->audioq, packet);
    } else {
      av_free_packet(packet);
    }
  }

рдпрд╣рд╛рдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдирдпрд╛ рдХреБрдЫ рднреА рдирд╣реАрдВ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрдм рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рдХрддрд╛рд░ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрддрдо рдЖрдХрд╛рд░ рд╣реИ, рдФрд░ рд╣рдордиреЗ рд░реАрдб рдПрд░рд░ рдЪреЗрдХрд┐рдВрдЧ рдХреЛ рдЬреЛрдбрд╝рд╛ рд╣реИред рдкреНрд░рд╛рд░реВрдк рдкреНрд░рд╕рдВрдЧ рдореЗрдВ рдПрдХ ByteIOContext рд╕рдВрд░рдЪрдирд╛ рд╣реИ, рдЬрд┐рд╕реЗ pb рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ред ByteIOContext рдПрдХ рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬреЛ рдореВрд▓ рд░реВрдк рд╕реЗ рдирд┐рдореНрди-рд╕реНрддрд░реАрдп рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреА рд╣реИред

рд╣рдорд╛рд░реЗ рд▓реВрдк рдХреЗ рдмрд╛рдж, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдпрд╛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реВрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╛рдХреА рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдХреЛрдб рд╣реИрдВред рдпрд╣ рдХреЛрдб рд╢рд┐рдХреНрд╖рд╛рдкреНрд░рдж рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдШрдЯрдирд╛рдУрдВ рдХреЛ рдХреИрд╕реЗ рдЖрдЧреЗ рдмрдврд╝рд╛рддреЗ рд╣реИрдВ - рдХреБрдЫ рдРрд╕рд╛ рдЬреЛ рд╣рдореЗрдВ рдмрд╛рдж рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд╛рд╣рд┐рдП рд╣реЛрдЧрд╛

  while(!is->quit) {
    SDL_Delay(100);
  }

 fail:
  if(1){
    SDL_Event event;
    event.type = FF_QUIT_EVENT;
    event.user.data1 = is;
    SDL_PushEvent(&event);
  }
  return 0;

рд╣рдореЗрдВ SDL рдирд┐рд░рдВрддрд░ SDL_USEREVENT рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╕реНрдЯрдо рдИрд╡реЗрдВрдЯ рдХреЗ рд▓рд┐рдП рдорд╛рди рдорд┐рд▓рддреЗ рд╣реИрдВ ред рдкрд╣рд▓рд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрд╡реЗрдВрдЯ SDL_USEREVENT , рдЕрдЧрд▓реЗ SDL_USEREVENT + 1 , рдЖрджрд┐ рдкрд░ рд╕реЗрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП ред FF_QUIT_EVENT рдХреЛ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ SDL_USEREVENT + 1 рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ ред рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рднреА рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдпрд╣рд╛рдВ рд╣рдо рдЕрдкрдиреЗ рдкреЙрдЗрдВрдЯрд░ рдХреЛ рдПрдХ рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рдЕрдВрдд рдореЗрдВ, рд╣рдо SDL_PushEvent () рдХрд╣рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдИрд╡реЗрдВрдЯ рд▓реВрдк рд╕реНрд╡рд┐рдЪ рдореЗрдВ, рд╣рдо рдЗрд╕реЗ SDL_QUIT_EVENT рд╕реЗрдХреНрд╢рди рдореЗрдВ рдбрд╛рд▓рддреЗ рд╣реИрдВрд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рдерд╛ред рд╣рдо рдШрдЯрдирд╛рдУрдВ рдХреЗ рд╣рдорд╛рд░реЗ рдЪрдХреНрд░ рдХреЛ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рджреЗрдЦреЗрдВрдЧреЗ; рдЕрднреА рдХреЗ рд▓рд┐рдП, рдмрд╕ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЬрдм рд╣рдо FF_QUIT_EVENT рджрдмрд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдЗрд╕реЗ рдмрд╛рдж рдореЗрдВ рдкрдХрдбрд╝рддреЗ рд╣реИрдВ рдФрд░ рдирд┐рдХрд╛рд╕ рдзреНрд╡рдЬ рдХреЛ рд╕реНрд╡рд┐рдЪ рдХрд░рддреЗ рд╣реИрдВред

рдлреНрд░реЗрдо рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ: video_thread


рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдХреЛрдбреЗрдХ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рд╕реНрдЯреНрд░реАрдо рд╡реАрдбрд┐рдпреЛ рдХрддрд╛рд░ рд╕реЗ рдкреИрдХреЗрдЯ рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ, рд╡реАрдбрд┐рдпреЛ рдХреЛ рдлрд╝реНрд░реЗрдо рдореЗрдВ рдбрд┐рдХреЛрдб рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдХрддрд╛рд░ рдХрддрд╛рд░ рдХреЛ рдЫрд╡рд┐ рдХрддрд╛рд░ рдореЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдлрд╝реНрд░реЗрдо рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реИ :

int video_thread(void *arg) {
  VideoState *is = (VideoState *)arg;
  AVPacket pkt1, *packet = &pkt1;
  int frameFinished;
  AVFrame *pFrame;

  pFrame = av_frame_alloc();

  for(;;) {
    if(packet_queue_get(&is->videoq, packet, 1) < 0) {
      // means we quit getting packets
      break;
    }
    // Decode video frame
    avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet);

    // Did we get a video frame?
    if(frameFinished) {
      if(queue_picture(is, pFrame) < 0) {
	break;
      }
    }
    av_free_packet(packet);
  }
  av_free(pFrame);
  return 0;
}

рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЕрдм рддрдХ рд╕рдордЭрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рдордиреЗ рдпрд╣рд╛рдБ рдХреЗрд╡рд▓ avcodec_decode_video2 рдлрд╝рдВрдХреНрд╢рди рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рдИ , рдмрд╕ рдХреБрдЫ рддрд░реНрдХреЛрдВ рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛; рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реА рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдПрдХ AVStream рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╡рд╣рд╛рдВ рд╕реЗ рдЕрдкрдиреЗ рдХреЛрдбреЗрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдЕрдкрдиреЗ рд╡реАрдбрд┐рдпреЛ рдХрддрд╛рд░ рд╕реЗ рдкреИрдХреЗрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВ рдЬрдм рддрдХ рдХрд┐ рдХреЛрдИ рд╣рдореЗрдВ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ рдХрд╣рддрд╛ рд╣реИ рдпрд╛ рд╣рдореЗрдВ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рдорд┐рд▓рддреА рд╣реИред

рдХрддрд╛рд░ рдХрд╛ рдврд╛рдВрдЪрд╛


рдЖрдЗрдП рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ рдЬреЛ рд╣рдорд╛рд░реЗ рдбрд┐рдХреЛрдб рдХрд┐рдП рдЧрдП pFrame рдХреЛ рд╣рдорд╛рд░реА рдЫрд╡рд┐ рдХрддрд╛рд░ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ ред рдЪреВрдВрдХрд┐ рд╣рдорд╛рд░реА рдЫрд╡рд┐ рдХрддрд╛рд░ SDL рдХрд╛ рдПрдХ рдЙрдкрд░рд┐рд╢рд╛рдпреА рд╣реИ (рд╕рдВрднрд╡рдд: рд╡реАрдбрд┐рдпреЛ рдкреНрд░рджрд░реНрд╢рди рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рдХрдо рд╕рдВрдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП), рд╣рдореЗрдВ рдЕрдкрдиреЗ рдлреНрд░реЗрдо рдХреЛ рдЗрд╕рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЫрд╡рд┐ рдХрддрд╛рд░ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдбреЗрдЯрд╛ рд╡рд╣ рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдмрдирд╛рдпрд╛ рдерд╛:

typedef struct VideoPicture {
  SDL_Overlay *bmp;
  int width, height; /* source height & width */
  int allocated;
} VideoPicture;

рд╣рдорд╛рд░реА рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЗрди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдПрдХ рдмрдлрд░ рд╣реЛрддрд╛ рд╣реИ, рдЬрд╣рд╛рдВ рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╣рдореЗрдВ рдЦреБрдж SDL_Overlay рд╡рд┐рддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдзреНрд╡рдЬ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ, рдЬреЛ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдордиреЗ рдпрд╣ рдХрд┐рдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВ)ред

рдЗрд╕ рдХрддрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рджреЛ рдмрд┐рдВрджреБ рд╣реИрдВ - рд░рд╛рдЗрдЯ рдЗрдВрдбреЗрдХреНрд╕ рдФрд░ рд░реАрдб рдЗрдВрдбреЗрдХреНрд╕ред рд╣рдо рдпрд╣ рднреА рдЯреНрд░реИрдХ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рддрдиреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЪрд┐рддреНрд░ рдмрдлрд░ рдореЗрдВ рд╣реИрдВред рдХрддрд╛рд░ рдореЗрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкрд╣рд▓реЗ рдЕрдкрдиреЗ рдмрдлрд░ рдХреЛ рд╕рд╛рдл рд╣реЛрдиреЗ рддрдХ рдЗрдВрддрдЬрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ, рддрд╛рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реЗ рд╡реАрдбрд┐рдпреЛрдЪрд┐рддреНрд░ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЬрдЧрд╣ рд╣реЛ ред рдлрд┐рд░ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рд╣рдо рдЕрдкрдиреЗ рд░рд┐рдХреЙрд░реНрдб рдЗрдВрдбреЗрдХреНрд╕ рдореЗрдВ рдУрд╡рд░рд▓реЗ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ? рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдЖрдкрдХреЛ рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрджрд┐ рд╡рд┐рдВрдбреЛ рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рддреЛ рд╣рдореЗрдВ рдмрдлрд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рджрд┐рдЦрд╛рдирд╛ рд╣реЛрдЧрд╛!

int queue_picture(VideoState *is, AVFrame *pFrame) {

  VideoPicture *vp;
  int dst_pix_fmt;
  AVPicture pict;

  /* wait until we have space for a new pic */
  SDL_LockMutex(is->pictq_mutex);
  while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
	!is->quit) {
    SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  }
  SDL_UnlockMutex(is->pictq_mutex);

  if(is->quit)
    return -1;

  // windex is set to 0 initially
  vp = &is->pictq[is->pictq_windex];

  /* allocate or resize the buffer! */
  if(!vp->bmp ||
     vp->width != is->video_st->codec->width ||
     vp->height != is->video_st->codec->height) {
    SDL_Event event;

    vp->allocated = 0;
    alloc_picture(is);
    if(is->quit) {
      return -1;
    }
  }

рдЖрдЗрдП рдЖрд╡рдВрдЯрди_рдЪрд┐рддреНрд░ () рдлрд╝рдВрдХреНрд╢рди рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ :

void alloc_picture(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;

  vp = &is->pictq[is->pictq_windex];
  if(vp->bmp) {
    // we already have one make another, bigger/smaller
    SDL_FreeYUVOverlay(vp->bmp);
  }
  // Allocate a place to put our YUV image on that screen
  SDL_LockMutex(screen_mutex);
  vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,
				 is->video_st->codec->height,
				 SDL_YV12_OVERLAY,
				 screen);
  SDL_UnlockMutex(screen_mutex);
  vp->width = is->video_st->codec->width;
  vp->height = is->video_st->codec->height;  
  vp->allocated = 1;
}

рдЖрдкрдХреЛ рдлрд╝рдВрдХреНрд╢рди SDL_CreateYUVOverlay рдХреЛ рдкрд╣рдЪрд╛рдирдирд╛ рдЪрд╛рд╣рд┐рдП , рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдЕрдкрдиреЗ рдореБрдЦреНрдп рд▓реВрдк рд╕реЗ рдЗрд╕ рдЦрдВрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рд╣реИред рдпрд╣ рдХреЛрдб рдЕрдм рддрдХ рдпрдереЛрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдореНрдпреВрдЯреЗрдХреНрд╕ рд▓реЙрдХ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рджреЛ рдзрд╛рдЧреЗ рдПрдХ рд╕рд╛рде рд╕реНрдХреНрд░реАрди рдкрд░ рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ! рдпрд╣ рд╣рдорд╛рд░реЗ рдЖрдмрдВрдЯрди_рдЪрд┐рддреНрд░ рдХреЛ рдХрд┐рд╕реА рдЕрдиреНрдп рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рд╣рд╕реНрддрдХреНрд╖реЗрдк рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрдЧрд╛ рдЬреЛ рдЪрд┐рддреНрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ред (рд╣рдордиреЗ рдЗрд╕ рд▓реЙрдХ рдХреЛ рдПрдХ рд╡реИрд╢реНрд╡рд┐рдХ рдЪрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдмрдирд╛рдпрд╛ рдФрд░ рдЗрд╕реЗ рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдЖрд░рдВрдн рдХрд┐рдпрд╛ (); рдХреЛрдб рджреЗрдЦреЗрдВред) рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд╣рдо рд╡реАрдбрд┐рдпреЛрдЪрд┐рддреНрд░ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЪреМрдбрд╝рд╛рдИ рдФрд░ рдКрдВрдЪрд╛рдИ рд░рдЦрддреЗ рд╣реИрдВ , рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рд╡реАрдбрд┐рдпреЛ рдХрд╛ рдЖрдХрд╛рд░ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ рдирд╣реАрдВ рдмрджрд▓рддрд╛ рд╣реИред
рдареАрдХ рд╣реИ, рд╣рдордиреЗ рдЗрд╕реЗ рд╕реБрд▓рдЭрд╛ рд▓рд┐рдпрд╛ рд╣реИ, рдФрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░рд╛ рдУрд╡рд░рд▓реЗ YUV рд╣реИ, рд╕рдорд░реНрдкрд┐рдд рдФрд░ рдЫрд╡рд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИред рдЖрдЗрдП рдХрддрд╛рд░ рдореЗрдВ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ_рдЪрд┐рддреНрд░ рдФрд░ рдлрд╝реНрд░реЗрдо рдХреЛ рдХреЙрдкреА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХреЛ рджреЗрдЦреЗрдВред рдпрд╣ рд╣рд┐рд╕реНрд╕рд╛ рдЖрдкрдХреЛ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:

int queue_picture(VideoState *is, AVFrame *pFrame) {

  /* Allocate a frame if we need it... */
  /* ... */
  /* We have a place to put our picture on the queue */

  if(vp->bmp) {

    SDL_LockYUVOverlay(vp->bmp);
    
    dst_pix_fmt = PIX_FMT_YUV420P;
    /* point pict at the queue */

    pict.data[0] = vp->bmp->pixels[0];
    pict.data[1] = vp->bmp->pixels[2];
    pict.data[2] = vp->bmp->pixels[1];
    
    pict.linesize[0] = vp->bmp->pitches[0];
    pict.linesize[1] = vp->bmp->pitches[2];
    pict.linesize[2] = vp->bmp->pitches[1];
    
    // Convert the image into YUV format that SDL uses
    sws_scale(is->sws_ctx, (uint8_t const * const *)pFrame->data,
	      pFrame->linesize, 0, is->video_st->codec->height,
	      pict.data, pict.linesize);
    
    SDL_UnlockYUVOverlay(vp->bmp);
    /* now we inform our display thread that we have a pic ready */
    if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) {
      is->pictq_windex = 0;
    }
    SDL_LockMutex(is->pictq_mutex);
    is->pictq_size++;
    SDL_UnlockMutex(is->pictq_mutex);
  }
  return 0;
}

рдпрд╣рд╛рдБ, рдЗрд╕рдХрд╛ рдЕрдзрд┐рдХрд╛рдВрд╢ рднрд╛рдЧ рдХреЗрд╡рд▓ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣рдордиреЗ рдкрд╣рд▓реЗ рдЕрдкрдиреЗ рдлреНрд░реЗрдо рдХреЗ рд╕рд╛рде YUV рдУрд╡рд░рд▓реЗ рдХреЛ рдЖрдмрд╛рдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдерд╛ ред рдЕрдВрддрд┐рдо рдмрд┐рдЯ рдмрд╕ рдХрддрд╛рд░ рдореЗрдВ рд╣рдорд╛рд░реЗ рдореВрд▓реНрдп рдХреЛ "рдЬреЛрдбрд╝рддрд╛ рд╣реИ"ред рдХрддрд╛рд░ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рдЗрд╕рдореЗрдВ рдореВрд▓реНрдпреЛрдВ рдХреЛ рддрдм рддрдХ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐ рдпрд╣ рдкреВрд░реНрдг рди рд╣реЛ рдЬрд╛рдП, рдФрд░ рдЗрд╕рд╕реЗ рдкрдврд╝рдирд╛ рддрдм рд╣реЛрддрд╛ рд╣реИ рдЬрдм рдЗрд╕рдореЗрдВ рдХрдо рд╕реЗ рдХрдо рдХреБрдЫ рд╣реЛред рдЗрд╕рд▓рд┐рдП, рдпрд╣ рд╕рднреА рдХреЗ рдореВрд▓реНрдп рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ -> рдЪрд┐рддреНрд░рдХ_рд╕рд╛рдЗрдЬрд╝ , рдЬрд┐рд╕рд╕реЗ рд╣рдореЗрдВ рдЗрд╕реЗ рдмреНрд▓реЙрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рддреЛ, рд╣рдо рдпрд╣рд╛рдВ рдХреНрдпрд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ: рд░рд┐рдХреЙрд░реНрдб рдкреЙрдЗрдВрдЯрд░ рдмрдврд╝рд╛рдПрдВ (рдФрд░ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рд╢реБрд░реВ рдХрд░реЗрдВ), рддреЛ рдХрддрд╛рд░ рдХреЛ рдЕрд╡рд░реБрджреНрдз рдХрд░реЗрдВ рдФрд░ рдЗрд╕рдХреЗ рдЖрдХрд╛рд░ рдХреЛ рдмрдврд╝рд╛рдПрдВред рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рдардХ рдХреЛ рдкрддрд╛ рдЪрд▓ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рдХрддрд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рд╣реИ, рдФрд░ рдпрджрд┐ рдпрд╣ рд╣рдорд╛рд░реА рдХрддрд╛рд░ рдХреЛ рдкреВрд░реНрдг рдмрдирд╛рддрд╛ рд╣реИ, рдФрд░ рд╣рдорд╛рд░реЗ рд░рд┐рдХреЙрд░реНрдбрд░ рдХреЛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрддрд╛ рдЪрд▓ рдЬрд╛рдПрдЧрд╛ред

рд╡реАрдбрд┐рдпреЛ рдкреНрд░рджрд░реНрд╢рди


рдпрд╣ рд╕рдм рд╣рдорд╛рд░реЗ рд╡реАрдбрд┐рдпреЛ рдзрд╛рдЧреЗ рдХреЗ рд▓рд┐рдП рд╣реИ! рдЕрдм рд╣рдордиреЗ рд╕рднреА рдореБрдХреНрдд рд╕реВрддреНрд░ рдкреВрд░реЗ рдХрд░ рд▓рд┐рдП рд╣реИрдВ, рдПрдХ рдХреЛ рдЫреЛрдбрд╝рдХрд░ - рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд╣рдордиреЗ рд╢реЗрдбреНрдпреВрд▓_рд░реЗрдлреНрд░реЗрд╢ () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдмрд╣реБрдд рдкрд╣рд▓реЗ рдХреИрд╕реЗ рдХрд╣рд╛ рдерд╛ ? рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрдпрд╛ рд╣реБрдЖ рдЗрд╕ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

/* schedule a video refresh in 'delay' ms */
static void schedule_refresh(VideoState *is, int delay) {
  SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
}

SDL_AddTimer () рдПрдХ SDL рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХреЗрд╡рд▓ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреЗ рдмрд╛рдж рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдкрд░рд┐рднрд╛рд╖рд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓рдмреИрдХ рдХрд░рддрд╛ рд╣реИ (рдФрд░, рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рдХреБрдЫ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдкрд░рд┐рднрд╛рд╖рд┐рдд рдбреЗрдЯрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ)ред рд╣рдо рд╡реАрдбрд┐рдпреЛ рдЕрдкрдбреЗрдЯ рдХреЛ рд╢реЗрдбреНрдпреВрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ - рд╣рд░ рдмрд╛рд░ рдЬрдм рд╣рдо рдЗрд╕реЗ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдПрдХ рдЯрд╛рдЗрдорд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдПрдХ рдШрдЯрдирд╛ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░реЗрдЧрд╛, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ, рд╣рдорд╛рд░реЗ рдореБрдЦреНрдп () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдиреЗрдЧрд╛ рдЬреЛ рд╣рдорд╛рд░реА рдХрддрд╛рд░ рддрд╕реНрд╡реАрд░ рд╕реЗ рдПрдХ рдлреНрд░реЗрдо рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЙрд╕рдХреЗ! рдУрд╣! рдПрдХ рд╡рд╛рдХреНрдп рдореЗрдВ рддреАрди "рдХреМрди рд╕рд╛ / рдХреМрди рд╕рд╛ / рдХреМрди рд╕рд╛"! рддреЛ, рдЖрдЗрдП рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЗрд╕ рдШрдЯрдирд╛ рдХреЛ рдХрд░реЗрдВ - рдЖрдЧред рдпрд╣ рд╣рдореЗрдВ рднреЗрдЬрддрд╛ рд╣реИ:

static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {
  SDL_Event event;
  event.type = FF_REFRESH_EVENT;
  event.user.data1 = opaque;
  SDL_PushEvent(&event);
  return 0; /* 0 means stop timer */
}

рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ рд╢реБрднрд╛рд░рдВрдн рд╣рдорд╛рд░реЗ рдкреБрд░рд╛рдиреЗ рдорд┐рддреНрд░ рдиреЗ рдХрд┐рдпрд╛ рд╣реИред FF_REFRESH_EVENT рдХреЛ рдпрд╣рд╛рдВ SDL_USEREVENT + 1 рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ ред рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЬрдм рд╣рдо 0 рд╡рд╛рдкрд╕ рдЖрддреЗ рд╣реИрдВ, рддреЛ рдПрд╕рдбреАрдПрд▓ рдЯрд╛рдЗрдорд░ рдХреЛ рд░реЛрдХ рджреЗрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХреЙрд▓рдмреИрдХ рдлрд┐рд░ рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рдЕрдм рдЬрдм рд╣рдордиреЗ FF_REFRESH_EVENT рдХреЛ рдлрд┐рд░ рд╕реЗ рдмреБрд▓рд╛рдпрд╛ рд╣реИ , рддреЛ рд╣рдореЗрдВ рдЗрд╕реЗ рдЕрдкрдиреЗ рдИрд╡реЗрдВрдЯ рд▓реВрдк рдореЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

for(;;) {

  SDL_WaitEvent(&event);
  switch(event.type) {
  /* ... */
  case FF_REFRESH_EVENT:
    video_refresh_timer(event.user.data1);
    break;

рд╣рдореЗрдВ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдХреНрдпрд╛ рднреЗрдЬрддрд╛ рд╣реИ, рдЬреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╣рдорд╛рд░реА рдЫрд╡рд┐ рдХрддрд╛рд░ рд╕реЗ рдбреЗрдЯрд╛ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ:

void video_refresh_timer(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;
  
  if(is->video_st) {
    if(is->pictq_size == 0) {
      schedule_refresh(is, 1);
    } else {
      vp = &is->pictq[is->pictq_rindex];
      /* Timing code goes here */

      schedule_refresh(is, 80);
      
      /* show the picture! */
      video_display(is);
      
      /* update queue for next picture! */
      if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {
	is->pictq_rindex = 0;
      }
      SDL_LockMutex(is->pictq_mutex);
      is->pictq_size--;
      SDL_CondSignal(is->pictq_cond);
      SDL_UnlockMutex(is->pictq_mutex);
    }
  } else {
    schedule_refresh(is, 100);
  }
}

рдлрд┐рд▓рд╣рд╛рд▓, рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ: рдпрд╣ рдХрддрд╛рд░ рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИ рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рд╣реЛрддрд╛ рд╣реИ, рдЕрдЧрд▓реЗ рд╡реАрдбрд┐рдпреЛ рдлреНрд░реЗрдо рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯрд╛рдЗрдорд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рд╡реАрдбрд┐рдпреЛ_рдбрд┐рд╕рдкреНрд▓реЗ рдХреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реНрдХреНрд░реАрди рдкрд░ рд╡реАрдбрд┐рдпреЛ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ, рдлрд┐рд░ рдХрддрд╛рд░ рдкрд░ рдХрд╛рдЙрдВрдЯрд░ рдмрдврд╝рд╛рддрд╛ рд╣реИ, рдЬрдмрдХрд┐ рдЗрд╕рдХрд╛ рдЖрдХрд╛рд░ рдХрдо рдХрд░рддрд╛ рд╣реИред рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдо рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ vp рдХреЗ рд╕рд╛рде рдХреБрдЫ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ , рдФрд░ рдпрд╣рд╛рдБ рдХреНрдпреЛрдВ рд╣реИ: рдпрд╣ рдЖрдЧреЗ рд╣реИред рд▓реЗрдХрд┐рди рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рджред рдЬрдм рд╣рдо рдСрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╣рдо рд╕рдордп рдХреА рдЬрд╛рдирдХрд╛рд░реА рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рдпрд╣рд╛рдВ, рдЙрд╕ рдХреЛрдб рдХреА рдЬрдЧрд╣ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ рдЬрд╣рд╛рдВ рдЯрд┐рдкреНрдкрдгреА "рдЯрд╛рдЗрдорд┐рдВрдЧ рдХреЛрдб рдпрд╣рд╛рдБ рдЬрд╛рддрд╛ рд╣реИ" рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рдЗрд╕ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рд╣рдо рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдХрд┐ рд╣рдореЗрдВ рдХрд┐рддрдиреА рдЬрд▓реНрджреА рдЕрдЧрд▓рд╛ рд╡реАрдбрд┐рдпреЛ рдлреНрд░реЗрдо рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдлрд┐рд░ рд╢реЗрдбреНрдпреВрд▓_рдкреНрд░реЛрдлрд╝рд░ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдпрд╣ рдорд╛рди рджрд░реНрдЬ рдХрд░реЗрдВ()ред рдлрд┐рд▓рд╣рд╛рд▓, рд╣рдо рд╕рд┐рд░реНрдл 80 рдХреЗ рдПрдХ рдХрд╛рд▓реНрдкрдирд┐рдХ рдореВрд▓реНрдп рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддреЗ рд╣реИрдВред рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдЖрдк рдЗрд╕ рдореВрд▓реНрдп рдХрд╛ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдлрд┐рд▓реНрдо рдХреЗ рд▓рд┐рдП рдлрд┐рд░ рд╕реЗ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди: 1) рдпрд╣ рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж рдзреАрдорд╛ рд╣реЛрдирд╛ рд╢реБрд░реВ рд╣реЛ рдЬрд╛рдПрдЧрд╛ рдФрд░ 2) рдпрд╣ рдмрд╣реБрдд рдмреЗрд╡рдХреВрдл рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рднрд╡рд┐рд╖реНрдп рдореЗрдВ рд╣рдо рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░ рд▓реМрдЯ рдЖрдПрдВрдЧреЗред

рд╣рдо рд▓рдЧрднрдЧ рдХрд░ рдЪреБрдХреЗ рд╣реИрдВред рдХреЗрд╡рд▓ рдПрдХ рдХрд╛рдо рдХрд░рдирд╛ рдмрд╛рдХреА рд╣реИ: рд╡реАрдбрд┐рдпреЛ рджрд┐рдЦрд╛рдУ! рдпрд╣рд╛рдБ video_display рдлрд╝рдВрдХреНрд╢рди рд╣реИ :

void video_display(VideoState *is) {

  SDL_Rect rect;
  VideoPicture *vp;
  float aspect_ratio;
  int w, h, x, y;
  int i;

  vp = &is->pictq[is->pictq_rindex];
  if(vp->bmp) {
    if(is->video_st->codec->sample_aspect_ratio.num == 0) {
      aspect_ratio = 0;
    } else {
      aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) *
	is->video_st->codec->width / is->video_st->codec->height;
    }
    if(aspect_ratio <= 0.0) {
      aspect_ratio = (float)is->video_st->codec->width /
	(float)is->video_st->codec->height;
    }
    h = screen->h;
    w = ((int)rint(h * aspect_ratio)) & -3;
    if(w > screen->w) {
      w = screen->w;
      h = ((int)rint(w / aspect_ratio)) & -3;
    }
    x = (screen->w - w) / 2;
    y = (screen->h - h) / 2;
    
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_LockMutex(screen_mutex);
    SDL_DisplayYUVOverlay(vp->bmp, &rect);
    SDL_UnlockMutex(screen_mutex);
  }
}

рдЪреВрдВрдХрд┐ рд╕реНрдХреНрд░реАрди рдХрд┐рд╕реА рднреА рдЖрдХрд╛рд░ рдХреА рд╣реЛ рд╕рдХрддреА рд╣реИ (рд╣рдордиреЗ 640x480 рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдЗрд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓ рдЬрд╛рдП), рдЖрдкрдХреЛ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реА рдлрд┐рд▓реНрдо рдХреЗ рд▓рд┐рдП рдЖрдпрддрд╛рдХрд╛рд░ рдХреНрд╖реЗрддреНрд░ рдХрд┐рддрдирд╛ рдмрдбрд╝рд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рддреЛ, рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рд╣рдорд╛рд░реА рдлрд┐рд▓реНрдо рдХреЗ рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛ рд╣реЛрдЧрд╛, рдмрд╕ рдКрдВрдЪрд╛рдИ рд╕реЗ рд╡рд┐рднрд╛рдЬрд┐рдд рдЪреМрдбрд╝рд╛рдИред рдХреБрдЫ рдХреЛрдбреЗрдХреНрд╕ рдореЗрдВ рдирдореВрдиреЗ рдХрд╛ рдПрдХ рд╡рд┐рд╖рдо рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рд╣реЛрдЧрд╛, рдЬреЛ рдХрд┐ рдХреЗрд╡рд▓ рдПрдХ рдкрд┐рдХреНрд╕реЗрд▓ рдпрд╛ рдирдореВрдиреЗ рдХреА рдЪреМрдбрд╝рд╛рдИ / рдКрдВрдЪрд╛рдИ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдХреЛрдбреЗрдХ рд╕рдВрджрд░реНрдн рдореЗрдВ рдКрдБрдЪрд╛рдИ рдФрд░ рдЪреМрдбрд╝рд╛рдИ рдХреЗ рдорд╛рди рдХреЛ рдкрд┐рдХреНрд╕реЗрд▓ рдореЗрдВ рдорд╛рдкрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рдирдореВрдирд╛ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рдХреЗ рдЧреБрдгрди рдЕрдиреБрдкрд╛рдд рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИред рдХреБрдЫ рдХреЛрдбреЗрдХреНрд╕ 0 рдХрд╛ рдПрдХ рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рджрд┐рдЦрд╛рдПрдЧрд╛, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдкрд┐рдХреНрд╕реЗрд▓ рдХрд╛ рдЖрдХрд╛рд░ рдХреЗрд╡рд▓ 1x1 рд╣реИред рдлрд┐рд░ рд╣рдо рдлрд┐рд▓реНрдо рдХреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╕реНрдХреЗрд▓ рдХрд░рддреЗ рд╣реИрдВрддрд╛рдХрд┐ рдпрд╣ рд╕реНрдХреНрд░реАрди рдкрд░ рдЬреНрдпрд╛рджрд╛ рд╕реЗ рдЬреНрдпрд╛рджрд╛ рдлрд┐рдЯ рдмреИрдареЗред рдереЛрдбрд╝рд╛ рдЙрд▓рдЯрд╛& -3 рдХреЗрд╡рд▓ рдЪрд╛рд░ рдХреЗ рдирд┐рдХрдЯрддрдо рдЧреБрдгрдХреЛрдВ рдХрд╛ рдорд╛рди рдмрдврд╝рд╛рддрд╛ рд╣реИред рдлрд┐рд░ рдлрд┐рд▓реНрдо рдХреЛ рдХреЗрдиреНрджреНрд░рд┐рдд рдХрд░реЗрдВ рдФрд░рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП SDL_DisplayYUVOverlay ()рдХреЙрд▓рдХрд░реЗрдВ рдХрд┐ рд╕реНрдХреНрд░реАрди рдореНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдФрд░ рдпрд╣ рд╕рдм рд╣реИ? рд╣рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ? рдирдП VideoStruct рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЕрднреА рднреА рдСрдбрд┐рдпреЛ рдХреЛрдб рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдпреЗ рддреБрдЪреНрдЫ рдкрд░рд┐рд╡рд░реНрддрди рд╣реИрдВ рдЬреЛ рдирдореВрдирд╛ рдХреЛрдб рдореЗрдВ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдЦрд┐рд░реА рдЪреАрдЬрд╝ рдЬреЛ рд╣рдореЗрдВ рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ рд╡рд╣ рд╣реИ FFmpeg рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рдирд┐рдХрд╛рд╕ рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдХреЙрд▓рдмреИрдХ рдХреЛ рдмрджрд▓рдирд╛:

VideoState *global_video_state;

int decode_interrupt_cb(void) {
  return (global_video_state && global_video_state->quit);
}

рдореБрдЦреНрдп () рдореЗрдВ рдПрдХ рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд▓рд┐рдП global_video_state рд╕реЗрдЯ рдХрд░реЗрдВ ред рддреЛ рдпрд╣ рдмрд╛рдд рд╣реИ! рд╣рдо рд╕рдВрдХрд▓рди рдХрд░рддреЗ рд╣реИрдВ:



gcc -o tutorial04 tutorial04.c -lavutil -lavformat -lavcodec -lswscale -lz -lm \
`sdl-config --cflags --libs`

рдФрд░ рдмрд┐рдирд╛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд┐рдП рдлрд┐рд▓реНрдо рдХрд╛ рдЖрдирдВрдж рд▓реЗрдВ! рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ, рд╣рдо рдЕрдВрдд рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рдмрдирд╛рдПрдВрдЧреЗ !






рдЕрдзреНрдпрд╛рдп 5: рд╡реАрдбрд┐рдпреЛ рд╕рд┐рдВрдХ тЖР тЗС тЖТ


рдкреВрд░реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ tutorial05.c
// tutorial05.c
// A pedagogical video player that really works!
//
// Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, 
// and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
// With updates from https://github.com/chelyaev/ffmpeg-tutorial
// Updates tested on:
// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101, SDL 1.2.15
// on GCC 4.7.2 in Debian February 2015
// Use
//
// gcc -o tutorial05 tutorial05.c -lavformat -lavcodec -lswscale -lz -lm `sdl-config --cflags --libs`
// to build (assuming libavformat and libavcodec are correctly installed, 
// and assuming you have sdl-config. Please refer to SDL docs for your installation.)
//
// Run using
// tutorial04 myvideofile.mpg
//
// to play the video stream on your screen.

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <SDL.h>
#include <SDL_thread.h>

#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif

#include <stdio.h>
#include <assert.h>
#include <math.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

#define SDL_AUDIO_BUFFER_SIZE 1024
#define MAX_AUDIO_FRAME_SIZE 192000

#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)

#define AV_SYNC_THRESHOLD 0.01
#define AV_NOSYNC_THRESHOLD 10.0

#define FF_REFRESH_EVENT (SDL_USEREVENT)
#define FF_QUIT_EVENT (SDL_USEREVENT + 1)

#define VIDEO_PICTURE_QUEUE_SIZE 1

typedef struct PacketQueue {
  AVPacketList *first_pkt, *last_pkt;
  int nb_packets;
  int size;
  SDL_mutex *mutex;
  SDL_cond *cond;
} PacketQueue;


typedef struct VideoPicture {
  SDL_Overlay *bmp;
  int width, height; /* source height & width */
  int allocated;
  double pts;
} VideoPicture;

typedef struct VideoState {

  AVFormatContext *pFormatCtx;
  int             videoStream, audioStream;

  double          audio_clock;
  AVStream        *audio_st;
  AVCodecContext  *audio_ctx;
  PacketQueue     audioq;
  uint8_t         audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
  unsigned int    audio_buf_size;
  unsigned int    audio_buf_index;
  AVFrame         audio_frame;
  AVPacket        audio_pkt;
  uint8_t         *audio_pkt_data;
  int             audio_pkt_size;
  int             audio_hw_buf_size;  
  double          frame_timer;
  double          frame_last_pts;
  double          frame_last_delay;
  double          video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
  AVStream        *video_st;
  AVCodecContext  *video_ctx;
  PacketQueue     videoq;
  struct SwsContext *sws_ctx;

  VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];
  int             pictq_size, pictq_rindex, pictq_windex;
  SDL_mutex       *pictq_mutex;
  SDL_cond        *pictq_cond;
  
  SDL_Thread      *parse_tid;
  SDL_Thread      *video_tid;

  char            filename[1024];
  int             quit;
} VideoState;

SDL_Surface     *screen;
SDL_mutex       *screen_mutex;

/* Since we only have one decoding thread, the Big Struct
   can be global in case we need it. */
VideoState *global_video_state;

void packet_queue_init(PacketQueue *q) {
  memset(q, 0, sizeof(PacketQueue));
  q->mutex = SDL_CreateMutex();
  q->cond = SDL_CreateCond();
}
int packet_queue_put(PacketQueue *q, AVPacket *pkt) {

  AVPacketList *pkt1;
  if(av_dup_packet(pkt) < 0) {
    return -1;
  }
  pkt1 = av_malloc(sizeof(AVPacketList));
  if (!pkt1)
    return -1;
  pkt1->pkt = *pkt;
  pkt1->next = NULL;
  
  SDL_LockMutex(q->mutex);

  if (!q->last_pkt)
    q->first_pkt = pkt1;
  else
    q->last_pkt->next = pkt1;
  q->last_pkt = pkt1;
  q->nb_packets++;
  q->size += pkt1->pkt.size;
  SDL_CondSignal(q->cond);
  
  SDL_UnlockMutex(q->mutex);
  return 0;
}
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{
  AVPacketList *pkt1;
  int ret;

  SDL_LockMutex(q->mutex);
  
  for(;;) {
    
    if(global_video_state->quit) {
      ret = -1;
      break;
    }

    pkt1 = q->first_pkt;
    if (pkt1) {
      q->first_pkt = pkt1->next;
      if (!q->first_pkt)
	q->last_pkt = NULL;
      q->nb_packets--;
      q->size -= pkt1->pkt.size;
      *pkt = pkt1->pkt;
      av_free(pkt1);
      ret = 1;
      break;
    } else if (!block) {
      ret = 0;
      break;
    } else {
      SDL_CondWait(q->cond, q->mutex);
    }
  }
  SDL_UnlockMutex(q->mutex);
  return ret;
}

double get_audio_clock(VideoState *is) {
  double pts;
  int hw_buf_size, bytes_per_sec, n;
  
  pts = is->audio_clock; /* maintained in the audio thread */
  hw_buf_size = is->audio_buf_size - is->audio_buf_index;
  bytes_per_sec = 0;
  n = is->audio_ctx->channels * 2;
  if(is->audio_st) {
    bytes_per_sec = is->audio_ctx->sample_rate * n;
  }
  if(bytes_per_sec) {
    pts -= (double)hw_buf_size / bytes_per_sec;
  }
  return pts;
}

int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr) {

  int len1, data_size = 0;
  AVPacket *pkt = &is->audio_pkt;
  double pts;
  int n;

  for(;;) {
    while(is->audio_pkt_size > 0) {
      int got_frame = 0;
      len1 = avcodec_decode_audio4(is->audio_ctx, &is->audio_frame, &got_frame, pkt);
      if(len1 < 0) {
	/* if error, skip frame */
	is->audio_pkt_size = 0;
	break;
      }
      data_size = 0;
      if(got_frame) {
	data_size = av_samples_get_buffer_size(NULL, 
					       is->audio_ctx->channels,
					       is->audio_frame.nb_samples,
					       is->audio_ctx->sample_fmt,
					       1);
	assert(data_size <= buf_size);
	memcpy(audio_buf, is->audio_frame.data[0], data_size);
      }
      is->audio_pkt_data += len1;
      is->audio_pkt_size -= len1;
      if(data_size <= 0) {
	/* No data yet, get more frames */
	continue;
      }
      pts = is->audio_clock;
      *pts_ptr = pts;
      n = 2 * is->audio_ctx->channels;
      is->audio_clock += (double)data_size /
	(double)(n * is->audio_ctx->sample_rate);
      /* We have data, return it and come back for more later */
      return data_size;
    }
    if(pkt->data)
      av_free_packet(pkt);

    if(is->quit) {
      return -1;
    }
    /* next packet */
    if(packet_queue_get(&is->audioq, pkt, 1) < 0) {
      return -1;
    }
    is->audio_pkt_data = pkt->data;
    is->audio_pkt_size = pkt->size;
    /* if update, update the audio clock w/pts */
    if(pkt->pts != AV_NOPTS_VALUE) {
      is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
    }
  }
}

void audio_callback(void *userdata, Uint8 *stream, int len) {

  VideoState *is = (VideoState *)userdata;
  int len1, audio_size;
  double pts;

  while(len > 0) {
    if(is->audio_buf_index >= is->audio_buf_size) {
      /* We have already sent all our data; get more */
      audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts);
      if(audio_size < 0) {
	/* If error, output silence */
	is->audio_buf_size = 1024;
	memset(is->audio_buf, 0, is->audio_buf_size);
      } else {
	is->audio_buf_size = audio_size;
      }
      is->audio_buf_index = 0;
    }
    len1 = is->audio_buf_size - is->audio_buf_index;
    if(len1 > len)
      len1 = len;
    memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
    len -= len1;
    stream += len1;
    is->audio_buf_index += len1;
  }
}

static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {
  SDL_Event event;
  event.type = FF_REFRESH_EVENT;
  event.user.data1 = opaque;
  SDL_PushEvent(&event);
  return 0; /* 0 means stop timer */
}

/* schedule a video refresh in 'delay' ms */
static void schedule_refresh(VideoState *is, int delay) {
  SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
}

void video_display(VideoState *is) {

  SDL_Rect rect;
  VideoPicture *vp;
  float aspect_ratio;
  int w, h, x, y;
  int i;

  vp = &is->pictq[is->pictq_rindex];
  if(vp->bmp) {
    if(is->video_ctx->sample_aspect_ratio.num == 0) {
      aspect_ratio = 0;
    } else {
      aspect_ratio = av_q2d(is->video_ctx->sample_aspect_ratio) *
	is->video_ctx->width / is->video_ctx->height;
    }
    if(aspect_ratio <= 0.0) {
      aspect_ratio = (float)is->video_ctx->width /
	(float)is->video_ctx->height;
    }
    h = screen->h;
    w = ((int)rint(h * aspect_ratio)) & -3;
    if(w > screen->w) {
      w = screen->w;
      h = ((int)rint(w / aspect_ratio)) & -3;
    }
    x = (screen->w - w) / 2;
    y = (screen->h - h) / 2;
    
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_LockMutex(screen_mutex);
    SDL_DisplayYUVOverlay(vp->bmp, &rect);
    SDL_UnlockMutex(screen_mutex);

  }
}

void video_refresh_timer(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;
  double actual_delay, delay, sync_threshold, ref_clock, diff;
  
  if(is->video_st) {
    if(is->pictq_size == 0) {
      schedule_refresh(is, 1);
    } else {
      vp = &is->pictq[is->pictq_rindex];

      delay = vp->pts - is->frame_last_pts; /* the pts from last time */
      if(delay <= 0 || delay >= 1.0) {
	/* if incorrect delay, use previous one */
	delay = is->frame_last_delay;
      }
      /* save for next time */
      is->frame_last_delay = delay;
      is->frame_last_pts = vp->pts;

      /* update delay to sync to audio */
      ref_clock = get_audio_clock(is);
      diff = vp->pts - ref_clock;

      /* Skip or repeat the frame. Take delay into account
	 FFPlay still doesn't "know if this is the best guess." */
      sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;
      if(fabs(diff) < AV_NOSYNC_THRESHOLD) {
	if(diff <= -sync_threshold) {
	  delay = 0;
	} else if(diff >= sync_threshold) {
	  delay = 2 * delay;
	}
      }
      is->frame_timer += delay;
      /* computer the REAL delay */
      actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
      if(actual_delay < 0.010) {
	/* Really it should skip the picture instead */
	actual_delay = 0.010;
      }
      schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
      
      /* show the picture! */
      video_display(is);
      
      /* update queue for next picture! */
      if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {
	is->pictq_rindex = 0;
      }
      SDL_LockMutex(is->pictq_mutex);
      is->pictq_size--;
      SDL_CondSignal(is->pictq_cond);
      SDL_UnlockMutex(is->pictq_mutex);
    }
  } else {
    schedule_refresh(is, 100);
  }
}
      
void alloc_picture(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;

  vp = &is->pictq[is->pictq_windex];
  if(vp->bmp) {
    // we already have one make another, bigger/smaller
    SDL_FreeYUVOverlay(vp->bmp);
  }
  // Allocate a place to put our YUV image on that screen
  SDL_LockMutex(screen_mutex);
  vp->bmp = SDL_CreateYUVOverlay(is->video_ctx->width,
				 is->video_ctx->height,
				 SDL_YV12_OVERLAY,
				 screen);
  SDL_UnlockMutex(screen_mutex);

  vp->width = is->video_ctx->width;
  vp->height = is->video_ctx->height;
  vp->allocated = 1;

}

int queue_picture(VideoState *is, AVFrame *pFrame, double pts) {

  VideoPicture *vp;
  int dst_pix_fmt;
  AVPicture pict;

  /* wait until we have space for a new pic */
  SDL_LockMutex(is->pictq_mutex);
  while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
	!is->quit) {
    SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  }
  SDL_UnlockMutex(is->pictq_mutex);

  if(is->quit)
    return -1;

  // windex is set to 0 initially
  vp = &is->pictq[is->pictq_windex];

  /* allocate or resize the buffer! */
  if(!vp->bmp ||
     vp->width != is->video_ctx->width ||
     vp->height != is->video_ctx->height) {
    SDL_Event event;

    vp->allocated = 0;
    alloc_picture(is);
    if(is->quit) {
      return -1;
    }
  }

  /* We have a place to put our picture on the queue */

  if(vp->bmp) {

    SDL_LockYUVOverlay(vp->bmp);
    vp->pts = pts;
    
    dst_pix_fmt = PIX_FMT_YUV420P;
    /* point pict at the queue */

    pict.data[0] = vp->bmp->pixels[0];
    pict.data[1] = vp->bmp->pixels[2];
    pict.data[2] = vp->bmp->pixels[1];
    
    pict.linesize[0] = vp->bmp->pitches[0];
    pict.linesize[1] = vp->bmp->pitches[2];
    pict.linesize[2] = vp->bmp->pitches[1];
    
    // Convert the image into YUV format that SDL uses
    sws_scale(is->sws_ctx, (uint8_t const * const *)pFrame->data,
	      pFrame->linesize, 0, is->video_ctx->height,
	      pict.data, pict.linesize);
    
    SDL_UnlockYUVOverlay(vp->bmp);
    /* now we inform our display thread that we have a pic ready */
    if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) {
      is->pictq_windex = 0;
    }
    SDL_LockMutex(is->pictq_mutex);
    is->pictq_size++;
    SDL_UnlockMutex(is->pictq_mutex);
  }
  return 0;
}

double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) {

  double frame_delay;

  if(pts != 0) {
    /* if we have pts, set video clock to it */
    is->video_clock = pts;
  } else {
    /* if we aren't given a pts, set it to the clock */
    pts = is->video_clock;
  }
  /* update the video clock */
  frame_delay = av_q2d(is->video_ctx->time_base);
  /* if we are repeating a frame, adjust clock accordingly */
  frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
  is->video_clock += frame_delay;
  return pts;
}

int video_thread(void *arg) {
  VideoState *is = (VideoState *)arg;
  AVPacket pkt1, *packet = &pkt1;
  int frameFinished;
  AVFrame *pFrame;
  double pts;

  pFrame = av_frame_alloc();

  for(;;) {
    if(packet_queue_get(&is->videoq, packet, 1) < 0) {
      // means we quit getting packets
      break;
    }
    if(packet_queue_get(&is->videoq, packet, 1) < 0) {
      // means we quit getting packets
      break;
    }
    pts = 0;

    // Decode video frame
    avcodec_decode_video2(is->video_ctx, pFrame, &frameFinished, packet);

    if((pts = av_frame_get_best_effort_timestamp(pFrame)) == AV_NOPTS_VALUE) {
      pts = 0;
    }
    pts *= av_q2d(is->video_st->time_base);

    // Did we get a video frame?
    if(frameFinished) {
      pts = synchronize_video(is, pFrame, pts);
      if(queue_picture(is, pFrame, pts) < 0) {
	break;
      }
    }
    av_free_packet(packet);
  }
  av_frame_free(&pFrame);
  return 0;
}

int stream_component_open(VideoState *is, int stream_index) {

  AVFormatContext *pFormatCtx = is->pFormatCtx;
  AVCodecContext *codecCtx = NULL;
  AVCodec *codec = NULL;
  SDL_AudioSpec wanted_spec, spec;

  if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) {
    return -1;
  }

  codec = avcodec_find_decoder(pFormatCtx->streams[stream_index]->codec->codec_id);
  if(!codec) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  codecCtx = avcodec_alloc_context3(codec);
  if(avcodec_copy_context(codecCtx, pFormatCtx->streams[stream_index]->codec) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }


  if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) {
    // Set audio settings from codec info
    wanted_spec.freq = codecCtx->sample_rate;
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.channels = codecCtx->channels;
    wanted_spec.silence = 0;
    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
    wanted_spec.callback = audio_callback;
    wanted_spec.userdata = is;
    
    if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {
      fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
      return -1;
    }
    is->audio_hw_buf_size = spec.size;
  }
  if(avcodec_open2(codecCtx, codec, NULL) < 0) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  switch(codecCtx->codec_type) {
  case AVMEDIA_TYPE_AUDIO:
    is->audioStream = stream_index;
    is->audio_st = pFormatCtx->streams[stream_index];
    is->audio_ctx = codecCtx;
    is->audio_buf_size = 0;
    is->audio_buf_index = 0;
    memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
    packet_queue_init(&is->audioq);
    SDL_PauseAudio(0);
    break;
  case AVMEDIA_TYPE_VIDEO:
    is->videoStream = stream_index;
    is->video_st = pFormatCtx->streams[stream_index];
    is->video_ctx = codecCtx;

    is->frame_timer = (double)av_gettime() / 1000000.0;
    is->frame_last_delay = 40e-3;
    
    packet_queue_init(&is->videoq);
    is->video_tid = SDL_CreateThread(video_thread, is);
    is->sws_ctx = sws_getContext(is->video_ctx->width, is->video_ctx->height,
				 is->video_ctx->pix_fmt, is->video_ctx->width,
				 is->video_ctx->height, PIX_FMT_YUV420P,
				 SWS_BILINEAR, NULL, NULL, NULL
				 );
    break;
  default:
    break;
  }
}

int decode_thread(void *arg) {

  VideoState *is = (VideoState *)arg;
  AVFormatContext *pFormatCtx;
  AVPacket pkt1, *packet = &pkt1;

  int video_index = -1;
  int audio_index = -1;
  int i;

  is->videoStream=-1;
  is->audioStream=-1;

  global_video_state = is;

  // Open video file
  if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0)
    return -1; // Couldn't open file

  is->pFormatCtx = pFormatCtx;
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, is->filename, 0);
  
  // Find the first video stream

  for(i=0; i<pFormatCtx->nb_streams; i++) {
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO &&
       video_index < 0) {
      video_index=i;
    }
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&
       audio_index < 0) {
      audio_index=i;
    }
  }
  if(audio_index >= 0) {
    stream_component_open(is, audio_index);
  }
  if(video_index >= 0) {
    stream_component_open(is, video_index);
  }   

  if(is->videoStream < 0 || is->audioStream < 0) {
    fprintf(stderr, "%s: could not open codecs\n", is->filename);
    goto fail;
  }

  // main decode loop

  for(;;) {
    if(is->quit) {
      break;
    }
    // seek stuff goes here
    if(is->audioq.size > MAX_AUDIOQ_SIZE ||
       is->videoq.size > MAX_VIDEOQ_SIZE) {
      SDL_Delay(10);
      continue;
    }
    if(av_read_frame(is->pFormatCtx, packet) < 0) {
      if(is->pFormatCtx->pb->error == 0) {
	SDL_Delay(100); /* no error; wait for user input */
	continue;
      } else {
	break;
      }
    }
    // Is this a packet from the video stream?
    if(packet->stream_index == is->videoStream) {
      packet_queue_put(&is->videoq, packet);
    } else if(packet->stream_index == is->audioStream) {
      packet_queue_put(&is->audioq, packet);
    } else {
      av_free_packet(packet);
    }
  }
  /* all done - wait for it */
  while(!is->quit) {
    SDL_Delay(100);
  }

 fail:
  if(1){
    SDL_Event event;
    event.type = FF_QUIT_EVENT;
    event.user.data1 = is;
    SDL_PushEvent(&event);
  }
  return 0;
}

int main(int argc, char *argv[]) {

  SDL_Event       event;

  VideoState      *is;

  is = av_mallocz(sizeof(VideoState));

  if(argc < 2) {
    fprintf(stderr, "Usage: test <file>\n");
    exit(1);
  }
  // Register all formats and codecs
  av_register_all();
  
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    exit(1);
  }

  // Make a screen to put our video
#ifndef __DARWIN__
        screen = SDL_SetVideoMode(640, 480, 0, 0);
#else
        screen = SDL_SetVideoMode(640, 480, 24, 0);
#endif
  if(!screen) {
    fprintf(stderr, "SDL: could not set video mode - exiting\n");
    exit(1);
  }

  screen_mutex = SDL_CreateMutex();

  av_strlcpy(is->filename, argv[1], sizeof(is->filename));

  is->pictq_mutex = SDL_CreateMutex();
  is->pictq_cond = SDL_CreateCond();

  schedule_refresh(is, 40);

  is->parse_tid = SDL_CreateThread(decode_thread, is);
  if(!is->parse_tid) {
    av_free(is);
    return -1;
  }
  for(;;) {

    SDL_WaitEvent(&event);
    switch(event.type) {
    case FF_QUIT_EVENT:
    case SDL_QUIT:
      is->quit = 1;
      SDL_Quit();
      return 0;
      break;
    case FF_REFRESH_EVENT:
      video_refresh_timer(event.user.data1);
      break;
    default:
      break;
    }
  }
  return 0;

}

рдЪреЗрддрд╛рд╡рдиреА


рдЬрдм рдореИрдВрдиреЗ рдЗрд╕ рдЧрд╛рдЗрдб рдХреЛ рд▓рд┐рдЦрд╛ рдерд╛, рддреЛ рдореЗрд░реЗ рд╕рднреА рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛрдб ffplay.c рдХреЗ рддрддреНрдХрд╛рд▓реАрди рд╕рдВрд╕реНрдХрд░рдг рд╕реЗ рд▓рд┐рдП рдЧрдП рдереЗ ред рдЖрдЬ рдпрд╣ рдПрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ рдХрд╛рд░реНрдпрдХреНрд░рдо рд╣реИ, рдФрд░ FFmpeg рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдореЗрдВ рдЕрдкрдбреЗрдЯ (рдФрд░ ffplay.c рдореЗрдВ рд╣реА) рдиреЗ рдореВрд▓рднреВрдд рдкрд░рд┐рд╡рд░реНрддрди рдХрд┐рдП рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдХреЛрдб рдЕрднреА рднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреБрд░рд╛рдирд╛ рд╣реИ, рдФрд░ рдХрдИ рдЕрдиреНрдп рд╕реБрдзрд╛рд░ рд╣реИрдВ рдЬреЛ рдЗрд╕ рдЧрд╛рдЗрдб рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред

рд╡реАрдбрд┐рдпреЛ рдХреИрд╕реЗ рд╕рд┐рдВрдХ рдХрд░рддрд╛ рд╣реИ


рдЕрдм рддрдХ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд▓рдЧрднрдЧ рдмреЗрдХрд╛рд░ рдореВрд╡реА рдкреНрд▓реЗрдпрд░ рдерд╛ред рд╣рд╛рдВ, рдпрд╣ рд╡реАрдбрд┐рдпреЛ рдЪрд▓рд╛рддрд╛ рд╣реИ, рдФрд░ рд╣рд╛рдВ, рдпрд╣ рдСрдбрд┐рдпреЛ рдЪрд▓рд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдлреА рдирд╣реАрдВ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдПрдХ рдлрд┐рд▓реНрдо рдХрд╣реЗрдВрдЧреЗред рддреЛ рдлрд┐рд░ рд╣рдо рдХреНрдпрд╛ рдХрд░рддреЗ рд╣реИрдВ?

рдкреАрдЯреАрдПрд╕ рдФрд░ рдбреАрдЯреАрдПрд╕


рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдЗрд╕ рдмрд╛рдд рдХреА рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдХрд┐рддрдиреЗ рддреЗрдЬрд╝ рдФрд░ рдХрд┐рддрдиреЗ рд╕рдордп рдХреЗ рд▓рд┐рдП рдЪрд▓рд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдСрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдПрдХ рдирдореВрдирд╛ рджрд░ рд╣реИ, рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рдлрд╝реНрд░реЗрдо рд╣реИрдВред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЕрдЧрд░ рд╣рдо рдХреЗрд╡рд▓ рдлрд╝реНрд░реЗрдо рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рдХреЗ рдФрд░ рдлреНрд░реЗрдо рджрд░ рд╕реЗ рдЧреБрдгрд╛ рдХрд░рдХреЗ рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдореМрдХрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдзреНрд╡рдирд┐ рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рджреВрд╕рд░реЗ рд░рд╛рд╕реНрддреЗ рдкрд░ рдЬрд╛рдПрдВрдЧреЗред рдзрд╛рд░рд╛ рд╕реЗ рдкреИрдХреЗрдЯреНрд╕ рдореЗрдВ рддрдерд╛рдХрдерд┐рдд рдбрд┐рдХреЛрдбрд┐рдВрдЧ рдЯрд╛рдЗрдо рд╕реНрдЯреИрдореНрдк рд╣реЛ рд╕рдХрддрд╛ рд╣реИ ( DTS - d ecoding t ime s tamp рд╕реЗ ) рдФрд░ рдкреНрд░реЗрдЬреЗрдВрдЯреЗрд╢рди рдЯрд╛рдЗрдо рд╕реНрдЯреИрдореНрдк ( PTS - p resentation t ime s рд╕реЗрдЯреИрдореНрдк )ред рдЗрди рджреЛ рдЕрд░реНрдереЛрдВ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдпрд╣ рдЬрд╛рдирдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдлрд┐рд▓реНрдореЗрдВ рдХреИрд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рдХреА рдЬрд╛рддреА рд╣реИрдВред рдПрдордкреАрдИрдЬреА рдЬреИрд╕реЗ рдХреБрдЫ рдкреНрд░рд╛рд░реВрдк, рдмреА-рдлреНрд░реЗрдо ( рдмреЗрдб рдФрд░ рджреНрд╡рд┐-рджрд┐рд╢рд╛рддреНрдордХ, рдЗрдВрдЧреНрд▓реИрдВрдбред рджреНрд╡рд┐рджрд┐рд╢ ) рдХрд╣рддреЗ рд╣реИрдВред рджреЛ рдЕрдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рдлреНрд░реЗрдо рдХреЛ I- рдлреНрд░реЗрдо рдФрд░ P- рдлреНрд░реЗрдо рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ( I is internal , i nner , рдФрд░ P рдХрд╛ рдЕрд░реНрде рд╣реИ рдкреВрд░реНрд╡рд╛рдиреБрдорд╛рдирд┐рдд , p рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ )ред I- рдлреНрд░реЗрдо рдореЗрдВ рдкреВрд░реА рдЫрд╡рд┐ рд╣реЛрддреА рд╣реИред рдкреА рдлреНрд░реЗрдордкрд┐рдЫрд▓реЗ I- рдФрд░ P- рдлреНрд░реЗрдо рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдкрд┐рдЫрд▓реЗ рдлреНрд░реЗрдо рд╕реЗ рдЕрд▓рдЧ рд╣реЛрддреЗ рд╣реИрдВ, рдпрд╛ рдЖрдк рдЗрд╕рдХрд╛ рдирд╛рдо рднреА рджреЗ рд╕рдХрддреЗ рд╣реИрдВ - рдбреЗрд▓реНрдЯрд╛рд╕ред рдмреА-рдлреНрд░реЗрдо рдкреА-рдлреНрд░реЗрдо рдХреЗ рд╕рдорд╛рди рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкрд┐рдЫрд▓реЗ рдФрд░ рдмрд╛рдж рдХреЗ рджреЛрдиреЛрдВ рдлреНрд░реЗрдо рдореЗрдВ рдирд┐рд╣рд┐рдд рдЬрд╛рдирдХрд╛рд░реА рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддреЗ рд╣реИрдВ! рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдПрдХ рдлреНрд░реЗрдо рдореЗрдВ рд╕реНрд╡рдпрдВ рдЫрд╡рд┐ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдиреНрдп рдлрд╝реНрд░реЗрдореЛрдВ рдХреЗ рд╕рд╛рде рдЕрдВрддрд░ - рдмрддрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпреЛрдВ рд╣рдореЗрдВ avcodec_decode_video2 рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рд╕рдорд╛рдкреНрдд рдлреНрд░реЗрдо рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ ред

рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдлрд┐рд▓реНрдо рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдЗрд╕ рдХреНрд░рдо рдореЗрдВ 4 рдлреНрд░реЗрдо рд╣реИрдВ: IBBP ред рддрдм рд╣рдореЗрдВ рдкрд┐рдЫрд▓реЗ рдкреА-рдлреНрд░реЗрдо рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ, рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдкрд┐рдЫрд▓реЗ рджреЛ рдмреА-рдлрд╝реНрд░реЗрдореЛрдВ рдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░ рд╕рдХреЗрдВред рдЗрд╕ рд╡рдЬрд╣ рд╕реЗ, рдлрд╝реНрд░реЗрдо рдХреЛ рдПрдХ рдЕрдиреБрдХреНрд░рдо рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдбрд┐рд╕реНрдкреНрд▓реЗ рдСрд░реНрдбрд░ рд╕реЗ рдореЗрд▓ рдирд╣реАрдВ рдЦрд╛рддрд╛: IPBBред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП рдбрд┐рдХреЛрдбрд┐рдВрдЧ рдЯрд╛рдЗрдо рд╕реНрдЯреИрдореНрдк рдФрд░ рдкреНрд░реЗрдЬреЗрдВрдЯреЗрд╢рди рдЯрд╛рдЗрдо рд╕реНрдЯреИрдореНрдк рд╣реИред рдбрд┐рдХреЛрдбрд┐рдВрдЧ рдЯрд╛рдЗрдо рд╕реНрдЯреИрдореНрдк рд╣рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдХрдм рдХреБрдЫ рдбреАрдХреЛрдб рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдкреНрд░реЗрдЬреЗрдВрдЯреЗрд╢рди рдЯрд╛рдЗрдо рд╕реНрдЯреИрдВрдк рд╣рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдХрдм рдХреБрдЫ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рддреЛ, рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдорд╛рд░реА рдзрд╛рд░рд╛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддреА рд╣реИ:

   PTS: 1 4 2 3
   DTS: 1 2 3 4
рд╕реНрдЯреНрд░реАрдо: IPBB

рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, PTS рдФрд░ DTS рдХреЗрд╡рд▓ рднрд┐рдиреНрди рд╣реЛрддреЗ рд╣реИрдВ, рдЬрдм рдЦреЗрд▓реЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдзрд╛рд░рд╛ рдореЗрдВ B- рдлреНрд░реЗрдо рд╣реЛрддреЗ рд╣реИрдВред

рдЬрдм рд╣рдо av_read_frame () рд╕реЗ рдПрдХ рдкреИрдХреЗрдЬ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ , рддреЛ рдЗрд╕рдореЗрдВ рдкреИрдХреЗрдЬ рдХреЗ рдЕрдВрджрд░ рдореМрдЬреВрдж рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП рдкреАрдЯреАрдПрд╕ рдФрд░ рдбреАрдЯреАрдПрд╕ рдорд╛рди рд╢рд╛рдорд┐рд▓ рд╣реЛрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЬрд┐рд╕ рдЪреАрдЬ рдХреА рдЬрд░реВрд░рдд рд╣реИ рд╡рд╣ рд╣реИ рд╣рдорд╛рд░реЗ рдирдП рдбреАрдХреЛрдб рдХрд┐рдП рдЧрдП рдХрдЪреНрдЪреЗ рдлреНрд░реЗрдо рдХрд╛ рдкреАрдЯреАрдПрд╕, рдЬрд┐рд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЗрд╕реЗ рдХрдм рджрд┐рдЦрд╛рдирд╛ рд╣реИред

рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, FFmpeg рд╣рдореЗрдВ "рд╕рд░реНрд╡реЛрддреНрддрдо рд╕рдВрднрд╡ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк" рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рд╣рдо av_frame_get_best_effort_timestamp () рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред

рддрд╛рджрд╛рддреНрдореНрдп


рдлрд╝реНрд░реЗрдо рдХреЛ рдмрджрд▓реЗ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЬрд╛рдирдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╡реАрдбрд┐рдпреЛ рдлрд╝реНрд░реЗрдо рдХреЛ рдХрдм рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПред рд▓реЗрдХрд┐рди рд╣рдо рдЗрд╕реЗ рдХреИрд╕реЗ рдХрд░рддреЗ рд╣реИрдВ? рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ: рдлреНрд░реЗрдо рджрд┐рдЦрд╛рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдЕрдЧрд▓рд╛ рдлреНрд░реЗрдо рдХрдм рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдлрд┐рд░ рдмрд╕ рд░реЛрдХреЗрдВ, рдЬрд┐рд╕рдХреЗ рдмрд╛рдж рд╣рдо рдЗрд╕ рдЕрд╡рдзрд┐ рдХреЗ рдмрд╛рдж рд╡реАрдбрд┐рдпреЛ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдЕрдкреЗрдХреНрд╖рд┐рдд рдерд╛, рд╣рдо рд╕рд┐рд╕реНрдЯрдо рдШрдбрд╝реА рдкрд░ рдЕрдЧрд▓реЗ рдлреНрд░реЗрдо рдХреЗ рдкреАрдЯреАрдПрд╕ рдорд╛рди рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░рд╛ рдкреНрд░рддреАрдХреНрд╖рд╛ рд╕рдордп рдХрд┐рддрдирд╛ рд▓рдВрдмрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рджреЛ рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╕рдВрдмреЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рдкрд╣рд▓рд╛, рд╕рд╡рд╛рд▓ рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд▓рд╛ рдкреАрдЯреАрдПрд╕ рдХрдм рд╣реЛрдЧрд╛? рдЖрдк рдХрд╣реЗрдВрдЧреЗ рдХрд┐ рдЖрдк рд╡реАрдбрд┐рдпреЛ рдЖрд╡реГрддреНрддрд┐ рдХреЛ рд╡рд░реНрддрдорд╛рди рдкреАрдЯреАрдПрд╕ рдореЗрдВ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ - рдФрд░ рдЖрдк рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рд╕рд╣реА рд╣реЛрдВрдЧреЗред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╡реАрдбрд┐рдпреЛ рдХреА рдХреБрдЫ рдХрд┐рд╕реНрдореЛрдВ рдХреЛ рджреЛрд╣рд░рд╛рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдлрд╝реНрд░реЗрдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдлреНрд░реЗрдо рдХреЛ рджреЛрд╣рд░рд╛рдирд╛ рд╣реЛрдЧрд╛ред рдЗрд╕рд╕реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдЕрдЧрд▓реА рдлреНрд░реЗрдо рдХреЛ рднреА рдЬрд▓реНрдж рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рдкрд░ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐, рдЗрд╕ рд╕рдордп рд╣рдордиреЗ рдЬреЛ рдХрд╛рд░реНрдпрдХреНрд░рдо рд▓рд┐рдЦрд╛ рд╣реИ, рдЙрд╕рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рдЦрд╝реБрд╢реА рд╕реЗ рдЖрдЧреЗ рдмрдврд╝ рд░рд╣реЗ рд╣реИрдВ, рдЬрдм рддрдХ рдХрд┐ рд╡реЗ рд╕рднреА рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реЗрд╢рд╛рди рди рд╣реЛрдВред рд╣рдореЗрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪрд┐рдВрддрд╛ рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рдирд╣реАрдВ рд╣реИ рдЕрдЧрд░ рд╕рдм рдХреБрдЫ рдЕрдкрдиреЗ рдЖрдк рд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЖрдкрдХрд╛ рдХрдВрдкреНрдпреВрдЯрд░ рд╕рд╣реА рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдХрдИ рд╡реАрдбрд┐рдпреЛ рдлрд╛рдЗрд▓реЗрдВ рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рддреАрди рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ: рдСрдбрд┐рдпреЛ рдХреЛ рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░реЗрдВ, рдСрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░реЗрдВ рдпрд╛ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рджреЛрдиреЛрдВ рдХреЛ рдмрд╛рд╣рд░реА рдШрдбрд╝реА рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░реЗрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЗ рдХрдВрдкреНрдпреВрдЯрд░ рдХреЗ рд╕рд╛рде)ред рдЕрдм рд╣рдо рдСрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред

рдХреЛрдбрд┐рдВрдЧ: рдПрдХ рдкреАрдЯреАрдПрд╕ рдлреНрд░реЗрдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛


рдЕрдм рд╕реАрдзреЗ рдХреБрдЫ рд▓рд┐рдЦрддреЗ рд╣реИрдВред рд╣рдореЗрдВ рдЕрдкрдиреА рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдХреБрдЫ рдФрд░ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рд╣рдо рдЗрд╕реЗ рдЕрдкрдиреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХрд░реЗрдВрдЧреЗред рдкрд╣рд▓реЗ, рдЖрдЗрдП рд╣рдорд╛рд░реЗ рд╡реАрдбрд┐рдпреЛ рдереНрд░реЗрдб рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рдпрд╣рд╛рдВ рд╣рдо рдЙрди рдкреИрдХреЗрдЯреЛрдВ рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдорд╛рд░реА рдбрд┐рдХреЛрдбрд┐рдВрдЧ рд╕реНрдЯреНрд░реАрдо рджреНрд╡рд╛рд░рд╛ рдХрддрд╛рд░рдмрджреНрдз рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ? рдХреЛрдб рдХреЗ рдЗрд╕ рднрд╛рдЧ рдореЗрдВ, рд╣рдореЗрдВ рдЙрд╕ рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП PTS рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ avcodec_decode_video2 рдиреЗ рд╣рдореЗрдВ рджрд┐рдпрд╛ рд╣реИ ред рдкрд╣рд▓рд╛ рддрд░реАрдХрд╛ рдЬрд┐рд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣рдордиреЗ рдмрд╛рдд рдХреА рд╣реИ, рд╡рд╣ рдЕрдВрддрд┐рдо рд╕рдВрд╕рд╛рдзрд┐рдд рдкреИрдХреЗрдЯ рдХрд╛ DTS рд╣реИ, рдЬреЛ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ:

  double pts;

  for(;;) {
    if(packet_queue_get(&is->videoq, packet, 1) < 0) {
      // means we quit getting packets
      break;
    }
    pts = 0;
    // Decode video frame
    len1 = avcodec_decode_video2(is->video_st->codec,
                                pFrame, &frameFinished, packet);
    if(packet->dts != AV_NOPTS_VALUE) {
      pts = av_frame_get_best_effort_timestamp(pFrame);
    } else {
      pts = 0;
    }
    pts *= av_q2d(is->video_st->time_base);

рдпрджрд┐ рд╣рдо рдЗрд╕рдХрд╛ рдореВрд▓реНрдп рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддреЛ рд╣рдо рдкреАрдЯреАрдПрд╕ рдХреЛ рд╢реВрдиреНрдп рдкрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред

рдЦреИрд░, рдпрд╣ рдЖрд╕рд╛рди рдерд╛ред рддрдХрдиреАрдХреА рдиреЛрдЯ: рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо рдкреАрдЯреАрдПрд╕ рдХреЗ рд▓рд┐рдП int64 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ ред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ PTS рдкреВрд░реНрдгрд╛рдВрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИред рдпрд╣ рдорд╛рди рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рд╣реИ рдЬреЛ рдЯрд╛рдЗрдордмрдм рдореЗрдВ рд╕рдордп рдХреЗ рдЖрдпрд╛рдо рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдзрд╛рд░рд╛ рдореЗрдВ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб 24 рдлреНрд░реЗрдо рд╣реИрдВ, рддреЛ 42 рд╕реЗ рдкреАрдЯреАрдПрд╕ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдЧрд╛ рдХрд┐ рдлреНрд░реЗрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдЙрд╕ рд╕реНрдерд╛рди рдкрд░ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд╣рд╛рдВ 42 рд╡рд╛рдВ рдлреНрд░реЗрдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдмрд╢рд░реНрддреЗ рдХрд┐ рд╣рдордиреЗ рд╣рд░ 1/24 рд╕реЗрдХрдВрдб рдореЗрдВ рдлреНрд░реЗрдо рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рд╣реЛ (рдмреЗрд╢рдХ, рдРрд╕рд╛ рдЬрд░реВрд░реА рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдЕрд╕рд▓ рдореЗрдВ)ред

рд╣рдо рдлреНрд░реЗрдо рджрд░ рд╕реЗ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдХреЗ рдЗрд╕ рдорд╛рди рдХреЛ рд╕реЗрдХрдВрдб рдореЗрдВ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред Time_base рдорд╛рдирдзрд╛рд░рд╛ рдлреНрд░реЗрдо рджрд░ (рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдлреНрд░реЗрдо рджрд░ рдХреЗ рд╕рд╛рде рд╕рд╛рдордЧреНрд░реА рдХреЗ рд▓рд┐рдП) рд╕реЗ рд╡рд┐рднрд╛рдЬрд┐рдд 1 рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдЧреА, рдЗрд╕рд▓рд┐рдП, рдкреАрдЯреАрдПрд╕ рдХреЛ рд╕реЗрдХрдВрдб рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо time_base рд╕реЗ рдЧреБрдгрд╛ рдХрд░рддреЗ рд╣реИрдВ ред

рдЖрдЧреЗ рдХреЛрдб: рдкреАрдЯреАрдПрд╕ рдХрд╛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдФрд░ рдЙрдкрдпреЛрдЧ


рддреЛ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╕рднреА рддреИрдпрд╛рд░ рдкреАрдЯреАрдПрд╕ рд╣реИрдВред рдЕрдм рд╣рдо рдЙрди рджреЛ рддреБрд▓реНрдпрдХрд╛рд▓рди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рдзреНрдпрд╛рди рд░рдЦреЗрдВрдЧреЗ, рдЬрд┐рдирдХреА рдЪрд░реНрдЪрд╛ рдереЛрдбрд╝реА рдЕрдзрд┐рдХ рдереАред рд╣рдо рдПрдХ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝_рд╡реАрдбрд┐рдпреЛ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рдкреАрдЯреАрдПрд╕ рдХреЛ рд╕рдм рдХреБрдЫ рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдбреЗрдЯ рдХрд░реЗрдЧрд╛ред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди, рдЖрдЦрд┐рд░рдХрд╛рд░, рдЙрди рдорд╛рдорд▓реЛрдВ рд╕реЗ рднреА рдирд┐рдкрдЯреЗрдЧрд╛ рдЬрд╣рд╛рдВ рд╣рдореЗрдВ рдЕрдкрдиреЗ рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП рдкреАрдЯреАрдПрд╕ рдорд╛рди рдирд╣реАрдВ рдорд┐рд▓рддрд╛ рд╣реИред рдЙрд╕реА рд╕рдордп, рд╣рдореЗрдВ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрдм рдЕрдЧрд▓реЗ рдлреНрд░реЗрдо рдХреА рдЙрдореНрдореАрдж рд╣реИ рддрд╛рдХрд┐ рд╣рдо рддрд╛рдЬрд╝рд╛ рджрд░ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░ рд╕рдХреЗрдВред рд╣рдо рдЖрдВрддрд░рд┐рдХ video_clock рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдРрд╕рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ , рдЬреЛ рдпрд╣ рдЯреНрд░реИрдХ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╡реАрдбрд┐рдпреЛ рдХреЗ рд▓рд┐рдП рдХрд┐рддрдирд╛ рд╕рдордп рдмреАрдд рдЪреБрдХрд╛ рд╣реИред рд╣рдо рдЗрд╕ рдореВрд▓реНрдп рдХреЛ рдЕрдкрдиреА рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:

typedef struct VideoState {
  double          video_clock; // pts of last decoded frame / predicted pts of next decoded frame

рдпрд╣рд╛рдБ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝_рд╡рд┐рдбрд┐рдпреЛ рдлрдВрдХреНрд╢рди рд╣реИ , рдЬреЛ рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рд╣реИ:

double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) {

  double frame_delay;

  if(pts != 0) {
    /* if we have pts, set video clock to it */
    is->video_clock = pts;
  } else {
    /* if we aren't given a pts, set it to the clock */
    pts = is->video_clock;
  }
  /* update the video clock */
  frame_delay = av_q2d(is->video_st->codec->time_base);
  /* if we are repeating a frame, adjust clock accordingly */
  frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
  is->video_clock += frame_delay;
  return pts;
}

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рджреЛрд╣рд░рд╛рдП рдЧрдП рдлрд╝реНрд░реЗрдореЛрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реИрдВред

рдЕрдм, рд╣рдо рдЕрдкрдирд╛ рд╕рд╣реА PTS рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рдирдпрд╛ pts рддрд░реНрдХ рдЬреЛрдбрд╝рдХрд░ queue_picture рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдлреНрд░реЗрдо рдХреЛ рдХрддрд╛рд░рдмрджреНрдз рдХрд░рддреЗ рд╣реИрдВ :

    // Did we get a video frame?
    if(frameFinished) {
      pts = synchronize_video(is, pFrame, pts);
      if(queue_picture(is, pFrame, pts) < 0) {
	break;
      }
    }

рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рд╣реИ рдХрд┐ queue_picture рд╣реИ рдХрд┐ рд╣рдо рдЗрд╕ рд╕реНрдЯреЛрд░ рд╣реИ рдЕрдВрдХ рдореВрд▓реНрдп рдореЗрдВ VideoPicture рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдХрд┐ рд╣рдо рдХрддрд╛рд░ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдореЗрдВ рдкреАрдЯреАрдПрд╕ рдЪрд░ рдХреЛ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдХреЛрдб рдХреА рдЗрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛:

typedef struct VideoPicture {
  ...
  double pts;
}
int queue_picture(VideoState *is, AVFrame *pFrame, double pts) {
  ... stuff ...
  if(vp->bmp) {
    ... convert picture ...
    vp->pts = pts;
    ... alert queue ...
  }

рддреЛ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╕рд╣реА PTS рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрддрд╛рд░рдмрджреНрдз рдЪрд┐рддреНрд░ рд╣реИрдВ, рддреЛ рдЪрд▓рд┐рдП рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рддреЗ рд╣реИрдВ рд╣рдорд╛рд░реЗ рд╡реАрдбрд┐рдпреЛ рдЕрдкрдбреЗрдЯ рдлреАрдЪрд░ рдкрд░ред рдЖрдк рдкрд┐рдЫрд▓реЗ рдкрд╛рда рд╕реЗ рдпрд╛рдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдордиреЗ рдЗрд╕реЗ рдлреЗрдХ рдХрд┐рдпрд╛ рдерд╛ рдФрд░ 80 рдПрдордПрд╕ рдХрд╛ рдЕрдкрдбреЗрдЯ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд┐рдпрд╛ рдерд╛ред рдЦреИрд░, рдЕрдм рд╣рдо рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╣рдорд╛рд░реА рд░рдгрдиреАрддрд┐ рдХреЗрд╡рд▓ рд╡рд░реНрддрдорд╛рди рдХреЗ рдмреАрдЪ рдХреЗ рд╕рдордп рдХреЛ рдорд╛рдкрдиреЗ рдХреЗ рджреНрд╡рд╛рд░рд╛ рдЕрдЧрд▓реЗ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдЯреЗрд▓реАрдлреЛрди рдХреЗ рд╕рдордп рдХреА рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ рдЕрдВрдХ рдФрд░ рдкрд┐рдЫрд▓реЗ рдПрдХред рдЙрд╕реА рд╕рдордп, рд╣рдореЗрдВ рдСрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо рдПрдХ рдСрдбрд┐рдпреЛ рдШрдбрд╝реА рдмрдирд╛рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред: рдПрдХ рдЖрдВрддрд░рд┐рдХ рдореВрд▓реНрдп рдЬреЛ рд╣рдо рдЦреЗрд▓ рд░рд╣реЗ рдСрдбрд┐рдпреЛ рдХреА рд╕реНрдерд┐рддрд┐ рдХрд╛ рдЯреНрд░реИрдХ рд░рдЦрддрд╛ рд╣реИред рдпрд╣ рдХрд┐рд╕реА рднреА рдПрдордкреА 3 рдкреНрд▓реЗрдпрд░ рдкрд░ рдбрд┐рдЬрд┐рдЯрд▓ рд░реАрдбрдЖрдЙрдЯ рдХреА рддрд░рд╣ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдо рд╡реАрдбрд┐рдпреЛ рдХреЛ рдзреНрд╡рдирд┐ рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рд╡реАрдбрд┐рдпреЛ рд╕реНрдЯреНрд░реАрдо рдЗрд╕ рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдпрд╣ рдмрд╣реБрдд рдЖрдЧреЗ рд╣реИ рдпрд╛ рдмрд╣реБрдд рдкреАрдЫреЗ рд╣реИред

рд╣рдо рдмрд╛рдж рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рд▓реМрдЯ рдЖрдПрдВрдЧреЗ; рдЕрдм рдорд╛рди рд▓реЗрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ get_audio_clock рдлрд╝рдВрдХреНрд╢рди рд╣реИрдЬреЛ рд╣рдореЗрдВ рдСрдбрд┐рдпреЛ рдШрдбрд╝реА рдкрд░ рд╕рдордп рджреЗрдЧрд╛ред рдЬреИрд╕реЗ рд╣реА рд╣рдореЗрдВ рдпрд╣ рдореВрд▓реНрдп рдорд┐рд▓рддрд╛ рд╣реИ, рдЕрдЧрд░ рд╡реАрдбрд┐рдпреЛ рдФрд░ рдСрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдХреНрдпрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ? рдпрд╣ рд╕рд┐рд░реНрдл рдПрдХ рдЦреЛрдЬ рдпрд╛ рдХреБрдЫ рдФрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рд╣реА рдкреИрдХреЗрдЬ рдкрд░ рдХреВрджрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдирд╛ рдореВрд░реНрдЦрддрд╛рдкреВрд░реНрдг рд╣реЛрдЧрд╛ред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдмрд╕ рдЙрд╕ рдореВрд▓реНрдп рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рд╣рдордиреЗ рдЕрдЧрд▓реЗ рдЕрджреНрдпрддрди рдХреЗ рд▓рд┐рдП рдЧрдгрдирд╛ рдХреА рдереА: рдпрджрд┐ рдкреАрдЯреАрдПрд╕ рдСрдбрд┐рдпреЛ рд╕рдордп рд╕реЗ рдмрд╣реБрдд рдкреАрдЫреЗ рд╣реИ, рддреЛ рд╣рдо рдЕрдкрдиреЗ рдЕрдиреБрдорд╛рдирд┐рдд рд╡рд┐рд▓рдВрдм рдХреЛ рджреЛрдЧреБрдирд╛ рдХрд░ рджреЗрддреЗ рд╣реИрдВред рдпрджрд┐ рдкреАрдЯреАрдПрд╕ рдЦреЗрд▓ рдХреЗ рд╕рдордп рд╕реЗ рдмрд╣реБрдд рдЖрдЧреЗ рд╣реИ, рддреЛ рд╣рдо рдЬрд▓реНрдж рд╕реЗ рдЬрд▓реНрдж рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЕрдм рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдЕрдкрдбреЗрдЯ рдпрд╛ рд╡рд┐рд▓рдВрдм рд╕рдордп рд╣реИ, рддреЛ рд╣рдо рдЕрдкрдиреЗ рдХрдВрдкреНрдпреВрдЯрд░ рдХреА рдШрдбрд╝реА рдХреЗ рд╕рд╛рде рдЗрд╕рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдлреНрд░реЗрдо_рдЯрд╛рдЗрдорд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИ ред рдпрд╣ рдлреНрд░реЗрдо рдЯрд╛рдЗрдорд░ рдореВрд╡реА рдкреНрд▓реЗрдмреИрдХ рдХреЗ рджреМрд░рд╛рди рд╣рдорд╛рд░реЗ рд╕рднреА рдЕрдиреБрдорд╛рдирд┐рдд рджреЗрд░реА рдХреЛ рд╕рд╛рд░рд╛рдВрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдпрд╣ рдлреНрд░реЗрдо_рдЯрд╛рдЗрдорд░- рдпрд╣ рд╡рд╣ рд╕рдордп рд╣реИ рдЬреЛ рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд▓реЗ рдлреНрд░реЗрдо рдХреЛ рдХрдм рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПред рд╣рдо рдмрд╕ рдлреНрд░реЗрдо рдЯрд╛рдЗрдорд░ рдореЗрдВ рдПрдХ рдирдИ рджреЗрд░реА рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдХрдВрдкреНрдпреВрдЯрд░ рдХреА рдШрдбрд╝реА рдкрд░ рд╕рдордп рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЕрдЧрд▓реЗ рдЕрдкрдбреЗрдЯ рдХреА рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдореВрд▓реНрдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдереЛрдбрд╝рд╛ рднреНрд░рд╛рдордХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХреЛрдб рдХреЛ рдзреНрдпрд╛рди рд╕реЗ рдкрдврд╝реЗрдВ:

void video_refresh_timer(void *userdata) {

  VideoState *is = (VideoState *)userdata;
  VideoPicture *vp;
  double actual_delay, delay, sync_threshold, ref_clock, diff;
  
  if(is->video_st) {
    if(is->pictq_size == 0) {
      schedule_refresh(is, 1);
    } else {
      vp = &is->pictq[is->pictq_rindex];

      delay = vp->pts - is->frame_last_pts; /* the pts from last time */
      if(delay <= 0 || delay >= 1.0) {
	/* if incorrect delay, use previous one */
	delay = is->frame_last_delay;
      }
      /* save for next time */
      is->frame_last_delay = delay;
      is->frame_last_pts = vp->pts;

      /* update delay to sync to audio */
      ref_clock = get_audio_clock(is);
      diff = vp->pts - ref_clock;

      /* Skip or repeat the frame. Take delay into account
	 FFPlay still doesn't "know if this is the best guess." */
      sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;
      if(fabs(diff) < AV_NOSYNC_THRESHOLD) {
	if(diff <= -sync_threshold) {
	  delay = 0;
	} else if(diff >= sync_threshold) {
	  delay = 2 * delay;
	}
      }
      is->frame_timer += delay;
      /* computer the REAL delay */
      actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
      if(actual_delay < 0.010) {
	/* Really it should skip the picture instead */
	actual_delay = 0.010;
      }
      schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
      /* show the picture! */
      video_display(is);
      
      /* update queue for next picture! */
      if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {
	is->pictq_rindex = 0;
      }
      SDL_LockMutex(is->pictq_mutex);
      is->pictq_size--;
      SDL_CondSignal(is->pictq_cond);
      SDL_UnlockMutex(is->pictq_mutex);
    }
  } else {
    schedule_refresh(is, 100);
  }
}

рд╣рдо рдХрдИ рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ: рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╡рд░реНрддрдорд╛рди рдкреАрдЯреАрдПрд╕ рдФрд░ рдкрд┐рдЫрд▓реЗ рдкреАрдЯреАрдПрд╕ рдХреЗ рдмреАрдЪ рдХреА рджреЗрд░реА рд╕рдордЭ рдореЗрдВ рдЖрддреА рд╣реИред рдпрджрд┐ рджреЗрд░реА рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдСрдбрд┐рдпреЛ рдФрд░ рд╡реАрдбрд┐рдпреЛ рд╕рд┐рд░реНрдл рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВ рдФрд░ рдмрд╕ рдЕрдВрддрд┐рдо рджреЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рддрдм рд╣рдо рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рдереНрд░реЗрд╢реЛрд▓реНрдб рдкреВрд░рд╛ рд╣реЛ рдЧрдпрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╕рд╣реА рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рдХрднреА рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред FFplay рдереНрд░реЗрд╢реЛрд▓реНрдб рдХреЗ рд▓рд┐рдП 0.01 рдХреЗ рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рд╣рдо рдпрд╣ рднреА рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдереНрд░реЗрд╢реЛрд▓реНрдб рдкреАрдЯреАрдПрд╕ рдореВрд▓реНрдпреЛрдВ рдХреЗ рдмреАрдЪ рдХреЗ рдЕрдВрддрд░рд╛рд▓ рд╕реЗ рдХрдо рдХрднреА рдирд╣реАрдВ рд╣реИред рдЕрдВрдд рдореЗрдВ, рдиреНрдпреВрдирддрдо рдЕрдкрдбреЗрдЯ рдорд╛рди 10 рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдкрд░ рд╕реЗрдЯ рдХрд░реЗрдВ (рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдпрд╣рд╛рдВ рдлреНрд░реЗрдо рдХреЛ рдЫреЛрдбрд╝ рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЪрд▓реЛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪрд┐рдВрддрд╛ рди рдХрд░реЗрдВ)ред

рд╣рдордиреЗ рдмрдбрд╝реА рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЪрд░ рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдЬреЛрдбрд╝рд╛, рддрд╛рдХрд┐ рдХреЛрдб рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рди рднреВрд▓реЗрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдлреНрд░реЗрдо рдЯрд╛рдЗрдорд░ рдФрд░ рдкрд┐рдЫрд▓реЗ рдлреНрд░реЗрдо рдХреЗ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╡рд┐рд▓рдВрдм рдХреЛ stream_component_open рдореЗрдВ рдЖрд░рдВрдн рдХрд░рдирд╛ рди рднреВрд▓реЗрдВ :

    is->frame_timer = (double)av_gettime() / 1000000.0;
    is->frame_last_delay = 40e-3;

рд╕рд┐рдВрдХ: рдСрдбрд┐рдпреЛ рдШрдбрд╝реА


рдСрдбрд┐рдпреЛ рдШрдбрд╝реА рдХреЛ рдорд╣рд╕реВрд╕ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рдЖ рдЧрдпрд╛ рд╣реИред рд╣рдо рдЕрдкрдиреЗ рдСрдбрд┐рдпреЛ_рдбрдмрд▓_рдлреНрд░реЗрдо рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдЙрд╕ рд╕рдордп рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ , рдЬрд╣рд╛рдВ рд╣рдо рдСрдбрд┐рдпреЛ рдХреЛ рдбреАрдХреЛрдб рдХрд░рддреЗ рд╣реИрдВред рдЕрдм рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд╣рдо рд╣рдореЗрд╢рд╛ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдкрд░ рд╣рд░ рдмрд╛рд░ рдПрдХ рдирдП рдкреИрдХреЗрдЬ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рджреЛ рдХреНрд╖реЗрддреНрд░ рд╣реИрдВ рдЬрд╣рд╛рдВ рдЖрдкрдХреЛ рдШрдбрд╝реА рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдкрд╣рд▓рд╛ рд╕реНрдерд╛рди рд╡рд╣ рд╣реИ рдЬрд╣рд╛рдВ рд╣рдореЗрдВ рдирдпрд╛ рдкреИрдХреЗрдЬ рдорд┐рд▓рддрд╛ рд╣реИ: рдмрд╕ рдкреАрдЯреАрдПрд╕ рдкреИрдХреЗрдЬ рдкрд░ рдзреНрд╡рдирд┐ рдШрдбрд╝реА рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВред рдлрд┐рд░, рдпрджрд┐ рдкреИрдХреЗрдЯ рдореЗрдВ рдХрдИ рдлрд╝реНрд░реЗрдо рд╣реИрдВ, рддреЛ рд╣рдо рдирдореВрдиреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рдХреЗ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рджрд┐рдП рдЧрдП рдирдореВрдиреЗ рдЖрд╡реГрддреНрддрд┐ рджреНрд╡рд╛рд░рд╛ рдЧреБрдгрд╛ рдХрд░рдХреЗ рдСрдбрд┐рдпреЛ рдкреНрд▓реЗрдмреИрдХ рд╕рдордп рдХреА рдмрдЪрдд рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкреИрдХреЗрдЬ рд╣реИ:

    /* if update, update the audio clock w/pts */
    if(pkt->pts != AV_NOPTS_VALUE) {
      is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
    }

рдФрд░ рдЬреИрд╕реЗ рд╣реА рд╣рдо рдкреИрдХреЗрдЬ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рддреЗ рд╣реИрдВ:

      /* Keep audio_clock up-to-date */
      pts = is->audio_clock;
      *pts_ptr = pts;
      n = 2 * is->audio_st->codec->channels;
      is->audio_clock += (double)data_size /
	(double)(n * is->audio_st->codec->sample_rate);

рдХреБрдЫ рдорд╛рдореВрд▓реА рдмрд╛рд░реАрдХрд┐рдпреЛрдВ: рдлрд╝рдВрдХреНрд╢рди рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдЕрдм pts_ptr рд╢рд╛рдорд┐рд▓ рд╣реИ , рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдмрджрд▓рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВред pts_ptr рд╡рд╣ рд╕реВрдЪрдХ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣рдо рдСрдбрд┐рдпреЛ_рдХреЙрд▓рдмреИрдХ рдСрдбрд┐рдпреЛ рдкреИрдХреЗрдЯ pts рдХреЛ рдмрддрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВ ред рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЕрдЧрд▓реА рдмрд╛рд░ рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рдСрдбрд┐рдпреЛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдЕрдм рд╣рдо рдЕрдВрдд рдореЗрдВ рдЕрдкрдиреЗ get_audio_clock рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред рдорд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЙрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИ -> рдСрдбрд┐рдпреЛ_рдХреНрд▓реЙрдХ , рдпрджрд┐ рдЖрдк рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрддреЗ рд╣реИрдВред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдо рд╣рд░ рдмрд╛рд░ рдЗрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддреЗ рд╕рдордп рдкреАрдЯреАрдПрд╕ рдСрдбрд┐рдпреЛ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдСрдбрд┐рдпреЛ_рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ, рдпрд╣ рд╣рдорд╛рд░реЗ рдСрдбрд┐рдпреЛ рдкреИрдХреЗрдЯ рд╕реЗ рд╣рдорд╛рд░реЗ рдЖрдЙрдЯрдкреБрдЯ рдмрдлрд░ рддрдХ рд╕рднреА рдбреЗрдЯрд╛ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдордп рд▓реЗрдЧрд╛ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╣рдорд╛рд░реА рдСрдбрд┐рдпреЛ рдШрдбрд╝реА рдореЗрдВ рдореВрд▓реНрдп рдмрд╣реБрдд рдЖрдЧреЗ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдореЗрдВ рдпрд╣ рдЬрд╛рдВрдЪрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдХрд┐рддрдирд╛ рд▓рд┐рдЦрдирд╛ рд╣реИред рдпрд╣рд╛рдБ рдкреВрд░рд╛ рдХреЛрдб рд╣реИ:

double get_audio_clock(VideoState *is) {
  double pts;
  int hw_buf_size, bytes_per_sec, n;
  
  pts = is->audio_clock; /* maintained in the audio thread */
  hw_buf_size = is->audio_buf_size - is->audio_buf_index;
  bytes_per_sec = 0;
  n = is->audio_st->codec->channels * 2;
  if(is->audio_st) {
    bytes_per_sec = is->audio_st->codec->sample_rate * n;
  }
  if(bytes_per_sec) {
    pts -= (double)hw_buf_size / bytes_per_sec;
  }
  return pts;
}

рдЕрдм рдЖрдкрдХреЛ рдпрд╣ рд╕рдордЭрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХреНрдпреЛрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ;)

рдЗрд╕рд▓рд┐рдП, рдпрд╣ рдмрд╛рдд рд╣реИ! рд╣рдо рд╕рдВрдХрд▓рди рдХрд░рддреЗ рд╣реИрдВ:

gcc -o tutorial05 tutorial05.c -lavutil -lavformat -lavcodec -lswscale -lz -lm \
`sdl-config --cflags --libs`

рдШрдЯрд┐рдд рд╣реБрдЖ! рдЖрдк рд╕реНрд╡-рдирд┐рд░реНрдорд┐рдд рдЦрд┐рд▓рд╛рдбрд╝реА рдкрд░ рдлрд┐рд▓реНрдо рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред рдЕрдЧрд▓реЗ рдкрд╛рда рдореЗрдВ, рд╣рдо рдСрдбрд┐рдпреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рджреЗрдЦреЗрдВрдЧреЗ, рдФрд░ рдлрд┐рд░ рдЦреЛрдЬ рдХрд░рдирд╛ рд╕реАрдЦреЗрдВрдЧреЗред

FFmpeg рдФрд░ SDL рдЧрд╛рдЗрдб рдпрд╛ 1000 рд╕реЗ рдХрдо рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рдХреИрд╕реЗ рд▓рд┐рдЦреЗрдВ - рднрд╛рдЧ 2



рдПрдбрд┐рд╕рди рдмреНрд▓реЙрдЧ рдкрд░ рдЕрдиреБрд╡рд╛рдж:


All Articles